I've wrote a custom UserStore for the ASP.NET Identity which I'm using it in an ASP.NET MVC 5.1 application. Everything is working as expected and I'm very happy with this new feature (Identity) of ASP.NET...
The issue is that I think is almost 2 days since I'm trying to return an error from the UpdateAsync method and somehow it seems that I'm not able to return anything.
LE: I'm using ASP.NET Identity Core 2.0.0-beta1
This is my code in few lines:
public Task UpdateAsync(IdentityUser user)
{
AdminUserEntity userEntity = new AdminUserEntity();
userEntity.IsNew = false;
userEntity.Id = user.UserModel.Id;
userEntity.UserCompleteName = user.UserModel.UserCompleteName;
userEntity.IsDisabled = user.UserModel.IsDisabled;
if (!String.IsNullOrEmpty(user.UserModel.PasswordHash))
userEntity.PasswordHash = user.UserModel.PasswordHash;
if (user.Claims != null && user.Claims.Count > 0)
{
foreach (Claim claim in user.Claims)
{
AdminUserClaimEntity claimEntity = userEntity.AdminUserClaims.AddNew();
claimEntity.AdminUserUniqueId = user.UserModel.UniqueId;
claimEntity.ClaimType = claim.Type;
claimEntity.ClaimValue = claim.Value;
}
}
try
{
byte[] timestamp = Convert.FromBase64String(user.UserModel.Timestamp);
AdminUserEntityManagement.UpdateCompleteAdminUserEntity(userEntity, timestamp);
}
catch (Exception exception)
{
List<string> errors = new List<string>() {exception.Message};
return Task.FromResult<IdentityResult>(IdentityResult.Failed(errors.ToArray()));
}
return Task.FromResult<object>(null);
}
Though there is an exception and the catch block is getting executed, the following line always returns success:
IdentityResult result = await UserManager.UpdateAsync(identityUser);
Can someone please tell me what am I missing?
I'm assuming this UpdateAsync is in your ApplicationUserManager class, shouldn't the signature be
public override Task<IdentityResult> UpdateAsync
if you are trying to change how the UserManager's UpdateAsync method works.
First of all, #hao-kung, thank you for your help. Now I can say that I've seen the big picture. Though I can't say that I like it, I understood how UserManager is working.
Also, if you think that I'm saying something wrong, please, correct me.
For the others, in order to customize UserManager behavior (even if you just want to surface an error which you are anyway able to catch in the UserStore custom class) you have to follow these steps (for better understanding I will exemplify by describing what I've did to catch a business exception for the UpdateAsync method and show it in the interface):
In the UserStore class (which should implement among other interfaces the IUserStore interface), don't catch any exception.
public Task UpdateAsync(IdentityUser user)
{
// here an exception will be thrown if there is a concurrency issue
byte[] timestamp = Convert.FromBase64String(user.UserModel.Timestamp);
AdminUserEntityManagement.UpdateCompleteAdminUserEntity(userEntity, timestamp);
return Task.FromResult<object>(null);
}
Extend UserManager class and override the method that you want to customize (catch the business exception thrown earlier and surface it to the interface):
public class AdminUserManager : UserManager<IdentityUser>
public override async Task<IdentityResult> UpdateAsync(IdentityUser user)
{
Task<IdentityResult> result = base.UpdateAsync(user);
try
{
IdentityResult identityResult = await result;
}
catch (Exception exception)
{
List<string> errors = new List<string>() { exception.Message };
return IdentityResult.Failed(errors.ToArray());
}
return result.Result;
}
In the MVC controller (for example) read the result of the UpdateAsync method from the extended UserManager class:
IdentityResult result = await UserManager.UpdateAsync(identityUser);
if (result.Succeeded)
{
this.SetNotification("The user has been updated.", EnumToastrNotificationType.Info);
return RedirectToAction("ShowUsers", "UserManagement");
}
else
{
this.AddErrors(result);
}
Related
Im really confused in .Netcore what normally should return to a queue(messagebroker),I have a class
public Task<IActionResult> GetMerchantPlatform(int merchantID) {
try
{
var mrchantInfo = dbContext.MerchantPlatforms.Where(s => s.Id == merchantID);
return Task.FromResult(mrchantInfo);
}
catch (Exception ex)
{
throw ex;
}
}
it gives me an error :Severity Code Description Project File Line Suppression State
Error CS0029 Cannot implicitly convert type 'System.Threading.Tasks.Task<System.Linq.IQueryable<Models.MerchantPlatform>>' to 'System.Threading.Tasks.Task<Microsoft.AspNetCore.Mvc.IActionResult>'
when should i return Iactionresult?and when should i return the class?and why im getting the above error?
By using the ControllerBase class you have to return an IActionResult or a Task<IActionResult>. There are plenty of pre-defined result objects available, which you can choose from, cause the result consist of multiple information that has to be defined by you. First is the HTTP status code that should be returned and depending on that you potentially have to return a body and/or some header entries.
If your method is within a ControllerBase class, there are already some helper methods within this class like Ok(), BadRequest(), Forbid(), NoContent(), NotFound(), etc. All with several overloads, depending on their usual use case.
So in your case, you probably have to write something like this:
public async Task<IActionResult> GetMerchantPlatform(int merchantID)
{
try
{
var mrchantInfo = await dbContext.MerchantPlatforms
.Where(s => s.Id == merchantID)
.ToListAsync();
return Ok(mrchantInfo);
}
catch (Exception ex)
{
return BadRequest(ex);
}
}
Be aware, that the try/catch is probably not needed in every function. For this purpose you can register your self-written middleware, that can put such a block around each action and act accordingly to your needs. But that's some stuff for another question or a search for
asp core middleware
And if you really want to only return the content in your method, you should consider to use the ApiControllerAttribute.
Scenario
I have a .NET Core 2.2 web API with an exception handling middleware. Whenever an exception occurs in the application (inside the MVC layer) it gets caught by the exception middleware and returned as an internal server error back to the frontend and logged to kibana.
The problem
This is all fine and well when things go wrong, but sometimes I want to notify the calling application of specifically what went wrong. I.e., "Could not find record in database!" or "Failed to convert this to that!"
My Solution
I've used application Exceptions (not great - I know) to piggy back off the error middleware to return this to the frontend. This has been working fine, but has created a lot of noise around the code by having to throw a whole bunch of exceptions. I'm not satisfied with this approach and convinced that there must be a better solution.
My application architecture: I'm following a traditional n-tier application layout being services (business logic) and repositories (DAL) all speaking to each other. I would preferably like to elegantly bubble up any issues back to the user in any of these layers.
I've been thinking about this for a while now and am not sure what the best way to go about it is. Any advice would be appreciated.
I use a kind of the operation result pattern (non-official pattern).
The principle is to return a new Type containing:
Whether the operation was a success.
The result of the operation if was successful.
Details about the Exception that caused the failure.
Consider the following class:
public class OperationResult
{
protected OperationResult()
{
this.Success = true;
}
protected OperationResult(string message)
{
this.Success = false;
this.FailureMessage = message;
}
protected OperationResult(Exception ex)
{
this.Success = false;
this.Exception = ex;
}
public bool Success { get; protected set; }
public string FailureMessage { get; protected set; }
public Exception Exception { get; protected set; }
public static OperationResult SuccessResult()
{
return new OperationResult();
}
public static OperationResult FailureResult(string message)
{
return new OperationResult(message);
}
public static OperationResult ExceptionResult(Exception ex)
{
return new OperationResult(ex);
}
public bool IsException()
{
return this.Exception != null;
}
}
Then you could easily adapt OperationResult or create a class that inherits from OperationResult, but uses a generic type parameter.
Some examples:
The Operation Result Pattern — A Simple Guide
Error Handling in SOLID C# .NET – The Operation Result Approach
As per the Microsoft's standards, it is ideal to use ProblemDetails object in case of 4xx/5xx exceptions -
Following is the customised RequestDelegate method which you can use in ApiExceptionHandler to handle exceptions.
public async Task RequestDelegate(HttpContext context)
{
var exception = context.Features.Get<IExceptionHandlerFeature>().Error;
var problemDetails = new ProblemDetails
{
Title = "An unexpected error occurred!",
Status = GetStatusCode(exception),
Detail = _env.IsDevelopment() ? exception.Message : "An unexpected error occurred!",
Instance = $"{Environment.MachineName}:{context.TraceIdentifier}:{Guid.NewGuid()}"
};
_logger.LogError($"Exception thrown. StatusCode: {problemDetails.Status}. Instance: {problemDetails.Instance}", exception);
context.Response.StatusCode = problemDetails.Status.Value;
context.Response.WriteJson(problemDetails, "application/problem + json");
await Task.CompletedTask;
}
I am using Microsoft.AspNet.Identity for logging into my c# mvc web application. I have implemented the different User Stores including the Lockout User Store. But I can't get it to work properly. In my Custom User Manager I set the max tries, lockout time etc:
manager.UserLockoutEnabledByDefault = true;
manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(30);
manager.MaxFailedAccessAttemptsBeforeLockout = 5;
If I use the above code and parameters my user never gets locked. If I set the manager.MaxFailedAccessAttemptsBeforeLockout to 2, the my User gets locked after one try. Does anyone have a tutorial on how to correctly implement the "IUserLockoutStore" interface? I've been searching Google all morning and am not getting closer to my goal. Here is my current implementation of the "IUserLockoutStore" interface.
public Task<DateTimeOffset> GetLockoutEndDateAsync(Gebruiker user)
{
var lockOutDate = user.LockOutDate.HasValue ? user.LockOutDate.Value : new DateTimeOffset(DateTime.Now.AddMinutes(-5));
return Task.FromResult(lockOutDate);
}
public Task SetLockoutEndDateAsync(Gebruiker user, DateTimeOffset lockoutEnd)
{
user.LockOutDate = lockoutEnd;
user.IsLocked = true;
return Context.SaveChangesAsync();
}
public Task<int> IncrementAccessFailedCountAsync(Gebruiker user)
{
user.LoginTry++;
return Context.SaveChangesAsync();
}
public Task ResetAccessFailedCountAsync(Gebruiker user)
{
user.LoginTry = 0;
return Context.SaveChangesAsync();
}
public Task<int> GetAccessFailedCountAsync(Gebruiker user) => Task.FromResult(user.LoginTry);
public Task<bool> GetLockoutEnabledAsync(Gebruiker user) => Task.FromResult(true);
public Task SetLockoutEnabledAsync(Gebruiker user, bool enabled)=> Task.FromResult(enabled);
My implementation is very similar to yours except for these two things:
In GetLockoutEndDateAsync I use utc time:
... new DateTimeOffset(DateTime.UtcNow.AddMinutes(-5))
Also (and perhaps more significantly), your return value from IncrementAccessFailedCountAsync should return the count (but you are returning the result of SaveChanges):
public Task<int> IncrementAccessFailedCountAsync(Gebruiker user)
{
user.LoginTry++;
Context.SaveChangesAsync();
return user.LoginTry;
}
It is just a coincidence that SaveChangesAsync also returns an int which is probably why you didn't notice this.
Another note is that you don't have to call Context.SaveChangesAsync() in the first place. This is handled by your implementation of IUserStore. Your IUserLockoutStore (and others like IUserLoginStore and IUserEmailStore etc) don't save to the DB. The infrastructure calls those interfaces to set things, then at the end call IUserStore.UpdateAsync (or .CreateAsync). So it should simply be:
public Task<int> IncrementAccessFailedCountAsync(Gebruiker user)
{
user.LoginTry++;
return Task.FromResult(user.LoginTry);
}
I'm using various resources to try and implement an Identity system with MS Access for an AngularJS app.
I created classes which implement the Identity interfaces I need, and I'm stuck at the stage of creating the Account controller (which will be the API for registeration, login, etc).
The class UserStore implements IUserStore and has the CreateAsync method:
public Task CreateAsync(TUser user)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
var result = userTable.Insert(user);
return Task.FromResult(result);
}
AccountController implements ApiController and has the Register method:
[AllowAnonymous]
[Route("register")]
public async Task<IHttpActionResult> Register(IdentityUser user)
{
var result = await _userStore.CreateAsync(user);
if (result == 0)
{
return InternalServerError();
}
return Ok();
}
userTable.Insert(user) returns an int indicating the number of rows affected in the DB table. The line var result = await _userStore.CreateAsync(user); throws an error, saying it actually returns void, and so void cannot be assigned to var (or to anything else).
I'm having a hard time understanding how to write the Register method and the CreateAsync method so that they will work together.
BTW, I thought I should give up the whole async thing and just make CreateAsync and Register return the int value as-is, but I can't do that since UserStore implements `IUserStore'.
The issue is that the return type cannot be passed from the CreateAsync as it is simply a Task return. It would need to be Task<int> but you cannot do that since it's implementing the IUserStore interface. Why do you need the result, I'm assuming you do not?
Try this instead:
[AllowAnonymous]
[Route("register")]
public async Task<IHttpActionResult> Register(IdentityUser user)
{
await _userStore.CreateAsync(user);
return Ok();
}
Additionally, consider making userTable.Insert(user) an async call if at all possible.
I would suggest not giving up on async/await. Especially for I/O bound operations on a web site like this, they really make your application usable.
If you're really concerned about whether or not the insert might be problematic, try this instead:
public async Task CreateAsync(TUser user)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
var existingUser = await this.FindByIdAsync(user.Id);
if (existingUser != null)
{
await this.UpdateAsync(user);
}
else
{
userTable.Insert(user);
}
}
I'm building a set of APIs. One of them is a authentication API, that returns JWT tokens. I'm trying to implement a Session per Action approach, with ActionFiltersAttribute. My controller is decorated with this attribute:
public class NHibernateSessionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var session = NHibernateSessionManager.SessionFactory.OpenSession();
session.BeginTransaction();
CurrentSessionContext.Bind(session);
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var session = CurrentSessionContext.Unbind(NHibernateSessionManager.SessionFactory)
if (session != null)
{
if (session.Transaction.IsActive)
{
try
{
session.Transaction.Commit();
}
catch
{
session.Transaction.Rollback();
}
}
session.Close();
}
}
}
Where is the problem? To manage the users with NHibernate istead of Entity Framework I've implemented all the needed ASP.NET Identity interfaces, and they all return a Task<T>. For example on the following action:
AccountController.cs
public async Task<IHttpActionResult> ChangePassword(ChangePasswordBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword,
model.NewPassword);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
There ChangePasswordAsync calls internally several methods wich have code inside new tasks, where the SessionFactory.GetCurrentSession() causes a NullException. As far as I know, because that's another Thread and context.
In code, the first attempt to save executes with no fail, and the second not. The duplicated code is only to ilustrate the situation.
UserStore.cs
public System.Threading.Tasks.Task UpdateAsync(UserModel user)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
//Here the Session is found
DataProviderI<UserModel, int> prov = new DataProviderImplGeneric<UserModel, int>();
prov.Save(user);
return Task.Factory.StartNew(() =>
{
//Here the Session is NOT found
DataProviderI<UserModel, int> prov2 = new DataProviderImplGeneric<UserModel, int>();
prov.Save(user);
});
}
What's the best way to deal with this and get the same ISession during all the Action ?
As far as I know NHibernate doesn't support async calls and I could refactorize the methods with a return of type Task.FromResult(0) on void cases or Task.FromResult<T>(T) where T is an object, but I would like to know if there's another solution to take advantage of parallelism
Seems like the problem you are dealing with is stemming from the HttpContext being null while inside a task and therefore cannot access the NHibernate session stored inside of the context variable.
You could work around this by getting the ISession before you call into a task.
Add in a constructor to your DataProviderImplGeneric so you manually pass one in.
DataProviderImplGeneric(ISession session) {
this.session = session;
}
just retrieve the session before you call into this from inside a task.
var session = GetCurrentNHibernateSession();
return Task.Factory.StartNew(() => {
var dataProvider = DataProviderImplGeneric<UserModel, int>(session);
return dataProvider.Save(user);
}