ASP.NET Identity Model First fails because of renamed AspNetUserRoles columns
Asked Answered
M

1

6

Like several others I have tried to implement ASP.NET Identity Model First. Everything works fine once you have tried, errored, fumed, searched and resolved.. I thought.

See also:

Course of action, summarized:

  • Created default project (MVC5)
  • Create database
  • Update connectionstring in the web.config
  • Run website, register: tables get created
  • Create EF Model (edmx)
  • Import Identity tables (everything fine up to this point)
  • Modified xxx.Context.tt to inherit from IdentityDbContext
  • Generate database script (trouble starts here)

I have solved the issues that appeared (up to the latest step). For completeness I will describe them.

Using the default Identity context

Everything works fine: tables get created, I can Register and login. This is however not the situation I want: I want to use a Model First approach.

Using the custom, model first context using the EF connectionstring

Modifying the CreatePerOwinContext so that it uses my Model First context:

public void ConfigureAuth(IAppBuilder app)
{
    app.CreatePerOwinContext(CustomModelFirstDbContext.Create);

And the ApplicationUserManager so that it uses the Model First context:

public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) 
{
    var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<CustomModelFirstDbContext>()));

Results in:

Server Error in '/' Application.

The entity type ApplicationUser is not part of the model for the current context.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: The entity type ApplicationUser is not part of the model for the current context.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace: [InvalidOperationException: The entity type ApplicationUser is not part of the model for the current context.]

Using the "normal" connectionstring with the custom, Model First context

An exception of type 'System.Data.Entity.Infrastructure.UnintentionalCodeFirstException' occurred in WebApplication1.dll but was not handled in user code

Additional information: Code generated using the T4 templates for Database First and Model First development may not work correctly if used in Code First mode. To continue using Database First or Model First ensure that the Entity Framework connection string is specified in the config file of executing application. To use these classes, that were generated from Database First or Model First, with Code First add any additional configuration using attributes or the DbModelBuilder API and then remove the code that throws this exception.

So, I figured I needed the default Identity context to use Identity, and use the custom Model First context for everything else. Not the preferred solution, but acceptable.

  • Rolled everything back
  • Import Identity tables from database
  • (Optional) Created entities via the Model First approach
  • Generated database script

Both the normal project and a quick sanity check test project have the same problem with the AspNetUserRoles table. That is a junction table, and when importing it in the EF designer, everything is OK. You won't see it since it is a many to many relationship, and when inspecting the association between AspNetRole and AspNetUser it looks good.

Designer and mapping details:

Model First mapping OK

However, when generating the sql script, EF modifies the keys.

Designer and mapping details:

enter image description here

Generated SQL script:

-- Creating table 'AspNetUserRoles'
CREATE TABLE [dbo].[AspNetUserRoles] (
[AspNetRoles_Id] nvarchar(128) NOT NULL,
[AspNetUsers_Id] nvarchar(128) NOT NULL
);
GO

In EF, you can't change the names of the mappings in the designer (thread on social.msdn.microsoft.com).

Subsequently the creation of a new user wil fail, using the originally created context because the junction table contains the wrong columns:

Server Error in '/' Application.

Invalid column name 'UserId'.

Invalid column name 'UserId'.

Invalid column name 'UserId'.

Invalid column name 'RoleId'.

Invalid column name 'UserId'.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.Data.SqlClient.SqlException: Invalid column name 'UserId'. Invalid column name 'UserId'. Invalid column name 'UserId'. Invalid column name 'RoleId'. Invalid column name 'UserId'.

Source Error:

Line 89: {

Line 90: var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };

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

Line 92: if (result.Succeeded)

Line 93: {

What is the solution? Are there any alternatives than trying to change the generated script, or moving to Code First?

Melchizedek answered 16/7, 2014 at 7:51 Comment(5)
I responded to this question in the comments on my blog. Please see that for more details (danieleagle.com/blog/2014/05/setting-up-asp-net-identity-framework-2-0-with-database-first-vs2013-update-2-spa-template/). If you have any luck with my suggestions I can post them as an answer to this question. I want to ensure it's helpful first so the rest of the community can benefit.Transmutation
Thanks for your detailed reply. If I might summarize, you are saying: (1) use Model First for designing the entities and database creation script (2) use SQL script generated from Code First to create Identity tables and relations (3) do not use the Model First approach for designing anything related to Identity? That would imply to me that Identity and Model First is not fully functional, and a workaround (like yours) is required.Melchizedek
Yes, that's correct. That is my current level of understanding. I'd be very happy to know if there is another way. The reality is the way Identity Framework 2.0 is implemented highly relies upon Code First. So at this point in time using it outside of Code First requires a bit of hacking and using workarounds. I'm hoping in future releases they make this easier. If anyone else knows of a better way I'd love to hear it as I'm sure you would as well.Transmutation
I sure hope so. Maybe someone like @DarinDimitrov knows the answer? :o)Melchizedek
Why exactly do you feel you absolutely must have your Identity context be model first?Gailey
U
0

If you in the begginning and db is still empty than I believe the easiest workaround is:

  1. Create EF Model(edmx).
  2. Right click on model "Generate Database from model".
  3. It will create DDL file (snippet below)
  4. Replace all wrong "AspNetUsers_Id" and "AspNetRoles_Id" for correct values.
  5. Right click "execute".

    Works for me. -- Creating non-clustered index for FOREIGN KEY 'FK_AspNetUserRoles_AspNetUser' CREATE INDEX [IX_FK_AspNetUserRoles_AspNetUser] ON [dbo].[AspNetUserRoles] ([AspNetUsers_Id]); //replace for UserId

Happy coding!

Unlawful answered 26/8, 2014 at 0:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.