3

When I register a user using the following code:

// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
    if (ModelState.IsValid)
    {
        var user = new ApplicationUser() { UserName = model.UserName };

        IdentityResult result = await UserManager.CreateAsync(user, model.Password);

        if (result.Succeeded)
        {
            await SignInAsync(user, isPersistent: false);
            return RedirectToAction("Index", "Home");
        }
        else
        {
            AddErrors(result);
        }

        return View(model);
    }
}

I am able to access all of the views with the [Authorize] attribute. However, if I log out and back in with the same user I get an error page with

"InvalidOperationException: UserId not found"

The error seems to be coming from my SignInAsync function at the statement:

var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);

I am not adding a UserID and there is no UserId field in the user classs (its Id) or in the AspNetUsers table. The user exists in that table, but again, there is no UserId.

I have tried clearing the cookies etc, but still no luck in re-logging in. Am I doing the register wrong? I don't understand why the authentication is looking for the UserId field when it doesn't seem to exist

EDIT: When I login the first time...i get the error page. However, when I reopen the page and it reads the cookie, I have access to everything. What the heck is going on with the initial login?

here is the SignInAsync method:

 private async Task SignInAsync(ApplicationUser user, bool isPersistent)
        {
            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
            var _identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);

            AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, _identity);
        }

inclusion:

 public class ApplicationUser : IdentityUser
    {
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Add custom user claims here
            return userIdentity;
        }
    }
8
  • Could you share your User model? Commented Jul 7, 2016 at 14:45
  • the User is an IPrinicipal implementation. i think its baked in. and the user object is an IdentityUser Commented Jul 7, 2016 at 14:49
  • Could you show us implementation of method SignInAsync(user, isPersistent: false);? Commented Jul 7, 2016 at 15:10
  • added. Thank you for your help, all Commented Jul 7, 2016 at 15:27
  • @rigamonk - You are showing two different CreateIdentityAsync. Which one are you referring to? You should also show what your ApplicationUser looks like as it may be related to stackoverflow.com/a/35017046/5233410. Commented Jul 15, 2016 at 15:34

1 Answer 1

0

Edit: I am wrong about you having mentioned Dapper, so the Dapper-specific details are not relevant, but the general idea of the fix remains - your Id and UserId columns are likely not getting matched up correctly.


I ran into this exact error yesterday. I think you previously had mentioned that you're using Dapper as the data access mechanism. I think that was perhaps relevant because you've also mentioned that the table has a Userid field, but your user class has an Id property. I am guessing you may also have some code to assign a new Guid to the Id property if there's not one there. Something like this:

public ApplicationUser()
{
    Id = Guid.NewGuid().ToString();
}

This combined with how Dapper mapping works may be messing you up since the Id field will wind up with that new Guid instead of the one it is supposed to be reading from the table.

In the below sample, Dapper is unable to assign the Id field of the ApplicationUser because the DB field is named differently than the property of the class. But it will already have an Id value from its constructor. This causes later calls to FindByIdAsync() and friends to fail.

public async Task<ApplicationUser> FindByNameAsync(string userName)
{
    ApplicationUser result = null;

    using (var conn = await GetOpenDBConnection())
    {
        try
        {
            // this query is bugged with Dapper because UserId does not
            // exist on ApplicationUser.
            var queryResults = await conn.QueryAsync<ApplicationUser>(
                "SELECT UserId, UserName, Email FROM dbo.Users WHERE UserName = @UserName;",
                new { UserName = userName });

            result = queryResults.FirstOrDefault();
        }
        catch (Exception ex)
        {
                            //handle error appropriately.
            result = null;
        }
    }

    return result;
}

If it is in fact a Dapper mapping issue, you can either rename the field in the query results such as SELECT UserId as [Id], UserName, Email FROM dbo.Users WHERE UserName = @UserName, or see Randall Stutton's answer for how to map Dapper fields in a really clean way.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.