how to use async await functionality with MVC / Membershipprovider - asp.net-mvc

I would like to authenticate user using Parse Library.
Here are the methods which I would like to make it asyc as api call supports only async call. I am new to MVC and aysc/await functionality.
Problem now is that it goes in await method and never returns result and view cant be loaded.
I spend quite some time understanding and trying to use different options but no success yet.
Do I need to use Partialviews or something can be done in ValidateUser method.
Any sample code is really appreciated.
Thanks.
AccountController.cs
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
{
var loggedIn = true;
}
return View(model);
}
ParseMembershipProvider : ExtendedMembershipProvider
public override bool ValidateUser(string username, string password)
{
var pUserRepo = new PUserRepository();
bool flag = false;
var requiredUser = pUserRepo.GetUserObjByUserName(username, password );
if (requiredUser.Result != null)
flag = true;
return flag;
}
PUserRepository.cs
public async Task<ParseUser> GetUserObjByUserName(string userName, string passWord)
{
return await ParseUser.LogInAsync("test1", "test123");
}

You're seeing a deadlock situation due to Result that I explain on my blog.
Unfortunately, membership providers are not (yet) async-aware. So try using ConfigureAwait(false) everywhere in your async methods:
public async Task<ParseUser> GetUserObjByUserName(string userName, string passWord)
{
return await ParseUser.LogInAsync("test1", "test123").ConfigureAwait(false);
}
(same for any other async methods you have).

Solution is
return Task.Run(() => ParseUser.LogInAsync(userName, passWord)).Result;
So basically I have sync wrapper around async method call. I understood from article that it depends also how that function in Parse library is using await or configureawait(false).

Related

Asp.NetCore UserStore slow user retrieval from database context

I have a weird situation which I don't understand. While testing my API I noticed slow api queries which boils down to retrieving the user from the store (after login).
When I override the FindByIdAsync method in my UserStore I can see a delay of 500ms when retrieving the User from the DbContext.
public override async Task<User> FindByIdAsync(string userId, CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();
if (!int.TryParse(userId, out int id))
{
return null;
}
// This takes 500+ ms
return Context.User.FirstOrDefault(u => u.Id == id);
}
Now the weird thing is when I do the same in a controller it is fast.
For example:
[HttpGet]
public async Task<IActionResult> Get()
{
// This function will end up at the UserStore.FindByIdAsync (see above)
// And takes 500+ ms
User user = await signInManager.UserManager.GetUserAsync(this.User);
// This however is fast... (just using a sample id)
context.User.Where(u => u.Id == 1896);
return Ok(await context.Session.Where(s => s.UserId == user.Id).ToListAsync());
}
I do not understand why this is. I tried swapping the two functions to see whether it was a warmup thing or something. But that is not the case..
I also looking in the source code from the UserStore and the Context there should be the same as the context in the Controller
I inject the context in the controller:
public SessionController(SignInManager<User> signInManager, MyDbContext context)
{
this.signInManager = signInManager;
// This is the same context as in the UserStore since the context is also injected in the UserStore
this.context = context;
}
Add ConfigureAwait(false) at the await call
User user = await signInManager.UserManager.GetUserAsync(this.User).ConfigureAwait(false);
await context.Session.Where(s => s.UserId == user.Id).ToListAsync().ConfigureAwait(false)

How to return an IHttpActionResult inside an MVC Controller?

I'm tinkering with an MVC Controller, having lifted some code out of an ApiController:
public class LoginController : Controller
{
public async Task<IHttpActionResult> Login(LoginModel model)
{
var success = await _accountClient.Login(model);
if (!success)
{
return new UnauthorizedResult(Enumerable.Empty<AuthenticationHeaderValue>(), new HttpRequestMessage());
}
return new OkResult(new HttpRequestMessage());
}
}
This just doesn't look or feel right, particularly the part where I'm creating a new HttpRequestMessage; I'm pretty sure that should somehow come from the incoming Request, but I can't figure out where that's supposed to come from.
Also, how do you create the IEnumerable<AuthenticationHeaderValue> object for the challenges parameter to the UnauthorizedResult constructor?
You can add headers to your Response object as
Response.AddHeader("Token","your-generated-token");
Also you can change your action method as
public async Task<HttpStatusCodeResult> Login(LoginModel model)
{
var success = await _accountClient.Login(model);
if (!success)
{
return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
}
return new HttpStatusCodeResult(HttpStatusCode.Ok);
}

Modifying login MVC 5 Asp Identity

I am using MVC 5 and Asp Identity for a new app I am building. I need to modify the login process so only information pertaining to the users community is shown. I was thinking of creating another table with Community ID's and User ID's in it similar to the AspUserRoles table. How do I tie this into the login process? Sorry I am new to MVC coming from Web Forms :(
Thanks!
Seems like a valid approach. So you'll end up with something like:
public class Community
{
...
public virtual ICollection<ApplicationUser> Members { get; set; }
}
public class ApplicationUser : IdentityUser
{
...
public virtual ICollection<Community> Communities { get; set; }
}
Entity Framework will automatically generate a join table from that. Then, in your login, somehow, you feed the community id. That could be from a special URL, a hidden input, select box, whatever. It's up to you. Then, you just need to modify the sign in process slighly. By default in a generated project template, sign in is handled via the following line:
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
You can see the code for PasswordSignInAsync here. But I'll post it here for posterity as well:
public virtual async Task<SignInResult> PasswordSignInAsync(string userName, string password,
bool isPersistent, bool shouldLockout)
{
var user = await UserManager.FindByNameAsync(userName);
if (user == null)
{
return SignInResult.Failed;
}
return await PasswordSignInAsync(user, password, isPersistent, shouldLockout);
}
So, just add your own version of this to ApplicationSignInManager in IdentiyConfig.cs:
public virtual async Task<SignInResult> PasswordSignInAsync(int communityId, string userName, string password,
bool isPersistent, bool shouldLockout)
{
var user = await UserManager.FindByNameAsync(userName);
if (user == null || !user.Communities.Any(m => m.Id == communityId))
{
return SignInResult.Failed;
}
return await PasswordSignInAsync(user, password, isPersistent, shouldLockout);
}
Notice the extra condition. Then, you just need to modify the original call in the Login action to pass in the communityId:
var result = await SignInManager.PasswordSignInAsync(communityId, model.Email, model.Password, model.RememberMe, shouldLockout: false);

How to implement PRG pattern and still use Ajax post response in asp mvc 4?

Our MVC Controllers inherit from a custom controller that removes the response (for PRG pattern):
protected override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (filterContext.HttpContext.Request.HttpMethod != #"GET")
{
Response.Clear();
}
}
On the client side, I am doing a simple save to the database:
var success = function (result) {
showNotification(result.Message, 'success', 3000);
hrp.load();
}
var inputArray = $(hoursForm + ' [name], ' + hoursFormId);
postAjaxArrayData('RoundingPolicies/SaveHoursRoundingPolicy', inputArray, success);
Which makes it to the controller fine, does the save, but since we are clearing out the response, the success() is not getting the result back from:
public void SaveHoursRoundingPolicy(HoursRoundingPolicyViewModel hoursRoundingPolicyViewModel) {
// Save
var json = new {
hoursRoundingPolicyViewModel.RoundingPolicyId,
hoursRoundingPolicyViewModel.Name,
Message = String.Format("Successfully Saved - ({0}) {1}", hoursRoundingPolicyViewModel.RoundingPolicyId, hoursRoundingPolicyViewModel.Name)
};
return Json(json);
}
How can we still implement the PRG pattern (by clearing the response on POSTs) but still get results back from Ajax POSTs? Can I distinguish between the two in OnResultExecuted()?
I would imagine this would be a fairly common scenario by anyone using PRG pattern with MVC, any thoughts on how to do this?
Why are you clearing the response? That's not really part of PRG... at least not in my experience.
In my experience using PRG, you accept the post, when/if it's successful you simply redirect to another action, which causes the GET, no need to clear the response.
Following the above pattern would still allow your AJAX posts to work like a normal post
// Simple implementation of PRG
[AcceptVerbs(HttpVerbs.Post)
public ActionResult Something(int value) {
return RedirectToAction("SomethingElse");
}
public ActionResult SomethingElse() {
return View();
}
// Simple implementation of standard post
[AcceptVerbs(HttpVerbs.Post)
public ActionResult SomethingAjax(int value) {
return Json(value);
}
EDITED for filterContext.Result Comparison
This should check the Action's return type and not apply the Response.Clear() to the Response when it's a JsonResult
protected override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (filterContext.HttpContext.Request.HttpMethod != #"GET" && !(filterContext.Result is JsonResult))
{
Response.Clear();
}
}
// Simple implementation of standard post
[AcceptVerbs(HttpVerbs.Post)
public JsonResult SomethingAjax(int value) {
return Json(value);
}

ASP .Net MVC 3: Unit testing controller actions

I am quite new to Unit testing and Mock concepts. I am trying to figure out how to write a good test case for the basic out-of-the box user registration code below:
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
MembershipCreateStatus createStatus;
Membership.CreateUser(model.UserName, model.Password, model.Email, null, null, true, null, out createStatus);
if (createStatus == MembershipCreateStatus.Success)
{
FormsAuthentication.SetAuthCookie(model.UserName, false /* createPersistentCookie */);
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("", ErrorCodeToString(createStatus));
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
Below are some of the specific points where I need your opinion/help:
I do not necessarily want to create a new user in ASP .Net membership database.
Based on the model passed in, how do I really make sure that if the user was successfully registered or there were errors in the process.
You have a problem with your code. Your action depends on a static method: Membership.CreateUser. And as you know static methods are PITAs to unit test.
So you could weaken the coupling by introducing a level of abstraction:
public interface IMyService
{
MembershipCreateStatus CreateUser(string username, string password, string email);
}
and then have some implementation that would use the current Membership provider:
public class MyService: IMyService
{
public MembershipCreateStatus CreateUser(string username, string password, string email)
{
MembershipCreateStatus status;
Membership.CreateUser(username, password, email, null, null, true, null, out status);
return status;
}
}
and finally the controller:
public class AccountController : Controller
{
private readonly IMyService _service;
public AccountController(IMyService service)
{
_service = service;
}
[HttpPost]
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
var status = _service.CreateUser(model.UserName, model.Password, model.Email);
if (status == MembershipCreateStatus.Success)
{
FormsAuthentication.SetAuthCookie(model.UserName, false /* createPersistentCookie */);
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("", ErrorCodeToString(createStatus));
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
}
OK, now that we have weakened the coupling we could use a mocking framework to mock the service in the unit test and make it trivial.
For example using Rhino Mocks you could create the following tests to cover the 2 failure cases:
[TestMethod]
public void Register_Action_Should_Redisplay_View_If_Model_Is_Invalid()
{
// arrange
var sut = new AccountController(null);
var model = new RegisterModel();
sut.ModelState.AddModelError("", "invalid email");
// act
var actual = sut.Register(model);
// assert
Assert.IsInstanceOfType(actual, typeof(ViewResult));
var viewResult = actual as ViewResult;
Assert.AreEqual(model, viewResult.Model);
}
[TestMethod]
public void Register_Action_Should_Redisplay_View_And_Add_Model_Error_If_Creation_Fails()
{
// arrange
var service = MockRepository.GenerateStub<IMyService>();
service
.Stub(x => x.CreateUser(null, null, null))
.IgnoreArguments()
.Return(MembershipCreateStatus.InvalidEmail);
var sut = new AccountController(service);
var model = new RegisterModel();
// act
var actual = sut.Register(model);
// assert
Assert.IsInstanceOfType(actual, typeof(ViewResult));
var viewResult = actual as ViewResult;
Assert.AreEqual(model, viewResult.Model);
Assert.IsFalse(sut.ModelState.IsValid);
}
The final test is the success case. We still have an issue with it. The issue is the following line:
FormsAuthentication.SetAuthCookie(model.UserName, false);
What is this? It is a static method call. So we proceed the same way as we did with the membership provider to weaken the coupling of our controller and the forms authentication system.
To test this method you can follow two way
Inside the test class create a new class that inherits from Membership class and override the method CreateUser.
Use Moq to mock the class.
For the first case I will check if username is equal to "GoodUser" or "BadUser" and generate a MembershipCreateStatus.Success or a different status.
For the second I will setup two method that follow the same idea as in the other method. See this link for an example

Resources