5

I wish to implement OWIN as per the example I could find here: http://www.asp.net/web-api/overview/security/individual-accounts-in-web-api

However, since this way of working is new to me especially using my self created database I would like some guidance. I can submit my registration request without a problem.

The post takes me to the AccountController:

    [AllowAnonymous]
    [Route("Register")]
    public async Task<IHttpActionResult> Register(RegisterBindingModel model)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        try { 
            var email = model.Email;
            var password = model.Password;

            var user = new users() {
                 Email = email,
                 PasswordHash = password,
                 Password = password
            };

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

            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            return Ok();
        }
        catch(Exception ex)
        {
            throw;
        }
    }

This triggers the below code:

    public ApplicationUserManager UserManager
    {
        get
        {
            return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
        }
        private set
        {
            _userManager = value;
        }
    }

ApplicationUserManager:

public class ApplicationUserManager : UserManager<users>
{
    public ApplicationUserManager(IUserStore<users> store)
        : base(store)
    {
    }

    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
    {
        var manager = new ApplicationUserManager(new UserStore<users>(context.Get<DaumAuctionEntities>()));
        var dataProtectionProvider = options.DataProtectionProvider;

        // Configure validation logic for passwords
        manager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = false,
            RequireDigit = false,
            RequireLowercase = true,
            RequireUppercase = true,
        };

        if (dataProtectionProvider != null)
        {
            manager.UserTokenProvider = new DataProtectorTokenProvider<users>(dataProtectionProvider.Create("ASP.NET Identity"));
        }

        return manager;
    }
}

But for some weird reason I'm getting

 modelState: {undefined: ["Name cannot be null or empty."]}

Even though I don't use name anywhere?! Where is this name coming from?

So I presume I'm doing something wrong but it's hard to debug without a clear explanation on how to implement OWIN with an existing DB.

Below my context/entity and users table that I would like to use to store me user data.

context:

public partial class DaumAuctionEntities : IdentityDbContext<users>
{
    public DaumAuctionEntities()
        : base("name=DaumAuctionEntities")
    {
    }

    public DbSet<addresses> addresses { get; set; }
    public DbSet<auctions> auctions { get; set; }
    public DbSet<images> images { get; set; }
    public DbSet<users> users { get; set; }
}

users : IdentityUser:

public partial class users : IdentityUser
{
    public override string UserName
    {
        get
        {
            return Email;
        }
        set
        {
            Email = value;
        }
    }

    override public string PasswordHash
    {
        get
        {
            return Password;
        }

        set
        {
            Password = value;
        }
    }

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<users> manager, string authenticationType)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
        // Add custom user claims here
        return userIdentity;
    }
}

public partial class users
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public System.DateTime CreatedDate { get; set; }
    public Nullable<System.DateTime> ModifiedDate { get; set; }

}

Edit:

If I add UserName back to my new users object before I try to call CreateAsync, the error is gone but I get another one instead:

"The specified type member 'UserName' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported."

Edit II:

I also have this issue in the tutorial code! This is just a freaking bug in .NET?

Edit III

I tried to do an override as you can see in the partial class Users above. But I still have the same error.

reaper_unique
  • 2,916
  • 3
  • 28
  • 48
  • Could you please submit your `DbContext` and `ApplicationUser` codes? – Sam FarajpourGhamari Feb 20 '16 at 15:15
  • Why you added properties like `ID`, `Email`, `Password`, ... ? By inheriting from `IdentityUser` your user object already has. Also when and in which line you get the error? – Sam FarajpourGhamari Feb 20 '16 at 15:27
  • The issue is due to the fact that I did not add UserName to my new user before I call UserManager.CreateAsync. If I add the UserName I have the exact same issue as this: http://stackoverflow.com/questions/28149599/mvc-5-identitydbcontext-and-dbcontext-transactions – reaper_unique Feb 20 '16 at 21:44
  • "Name cannot be null or empty." comes from `if (!ModelState.IsValid)`? – Arturo Menchaca Feb 26 '16 at 18:59
  • Nope, it actually passes that. It comes from I believe the manager but whenever I try to debug that code the debugger states that it jumped over it (most likely due to the fact that it's an external library from Microsoft). – reaper_unique Feb 27 '16 at 00:25
  • Have you a `UserName` column in your database? – Arturo Menchaca Feb 27 '16 at 02:56
  • @reaper_unique See my updated answer about "... whenever I try to debug that code the debugger states that it jumped over it " – George Vovos Feb 27 '16 at 11:03
  • @reaper_unique can you share your code on github, so that i can have a look at it? – jitendra singh Feb 29 '16 at 17:36
  • As of now i am downloading the project from your referenced link. Let's see if I am able to replicate your error. – jitendra singh Feb 29 '16 at 17:45

4 Answers4

0

The issue is due to the fact that I did not add UserName to my new user before I call UserManager.CreateAsync. If I add the UserName I have the exact same issue as this: MVC 5 IdentityDbContext and DbContext transactions

That issue seems to point to the fact that ASP.NET Identity is using the UserName property in a query, but Entity Framework compains that the property is not mapped to a database column in your Entity model (EDML).

Community
  • 1
  • 1
ErikHeemskerk
  • 1,623
  • 14
  • 30
  • But UserName and Email are both fields that I'm using from IdentityDbContext which has those two fields so they should be present, no? – reaper_unique Feb 22 '16 at 14:20
  • Fields are present in entity types (such as `users`), not context types (such as `IdentityContext`). – ErikHeemskerk Feb 22 '16 at 14:29
  • Yeah sorry that should be 'IdentityUser'. I'm using Email and UserName from IdentityUser. – reaper_unique Feb 22 '16 at 14:44
  • You need to explicitly map them; mapping inherited from a base class are ignored by Entity Framework. – ErikHeemskerk Feb 22 '16 at 15:12
  • How would I go about mapping IdentityUser fields to my own entities? Taking public partial class users as the base. – reaper_unique Feb 22 '16 at 15:47
  • It's no different from mapping any other column; SO and the rest of the internet should be able to answer that question. – ErikHeemskerk Feb 22 '16 at 16:12
  • I guess I'm not looking good enough because I really can't find what you are implying. Could you please give an example of an SO question that tackles this? – reaper_unique Feb 22 '16 at 16:55
  • This might help: http://stackoverflow.com/questions/19940014/asp-net-identity-with-ef-database-first-mvc5 – ErikHeemskerk Feb 22 '16 at 17:17
  • That doesn't work either. Still get the same error:The specified type member 'UserName' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported. – reaper_unique Feb 22 '16 at 19:27
0

I don't see many problems with your code

  1. Remove the users DbSet from your DaumAuctionEntities class (See this)
  2. Remove the Id property from your users class
  3. Set the CreatedDate property when you create a new users inside the Register method

Then you should be OK

Also,about:

Nope, it actually passes that. It comes from I believe the manager but whenever I try to debug that code the debugger states that it jumped over it (most likely due to the fact that it's an external library from Microsoft).

If you wrap the call with a try/catch you'll be able to see the error message

Community
  • 1
  • 1
George Vovos
  • 7,563
  • 2
  • 22
  • 45
0

I got few issues with the code you have shared here but not exactly the same as you mentioned. I have shared the example on git for your reference. Try it by your self and let me know if you see any issues.

Git URL - https://github.com/JitJDN/OWINStack

See, code is still the same as yours:

var email = model.Email; var password = model.Password;

        var user = new users()
        {
            Email = email,
            PasswordHash = password,
            Password = password
        };

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

        if (!result.Succeeded)
        {
            return GetErrorResult(result);
        }

        return Ok();
jitendra singh
  • 155
  • 1
  • 14
0

I finally got it working.

In the end I had to add adjust the partial class Users (which is a table in my SQL database) so that UserName and Password override the fields of IDentityUser (so not like I did in my question):

public partial class users
{
    public int Id { get; set; }
    public string UserName {get; set; }
    public string Password { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }    
    public DateTime? CreatedDate { get; set; }
    public DateTime? ModifiedDate { get; set; }
}

I then just had to pass the password and UserName when I created the user:

        var user = new users() {
             Email = email,
             UserName = email, 
             PasswordHash = password,
             Password = password
        };
reaper_unique
  • 2,916
  • 3
  • 28
  • 48