1

I'm beginner in ASP.NET MVC5.

My project solution has the structure as described in ASP.NET MVC5 Pro:

Solution
 -Project.Domain    --- C# Class Library
 -Project.WebUI     --- Empty ASP.Net MVC Project Template
 -Project.UnitTests

And I want to use ASP Identity 2.0 in it.

In Project.Domain I have Concrete (contexts, their initializers) and Entities (data models) foldiers.

I installed Identity 2.0 Samples as described here.

I split the IdentityModels.cs file into ApplicationDbContext.cs and ApplicationUser.cs, and put them in Concrete and Entities foldiers respectively.

Also in Concrete foldier I have EFDbContext.cs - separate from ApplicationDbContext context (they use the same database connection).

I wanted to store AppicationDbInitializer class (from Project.WebUI\App_Start\IdentityConfig.cs) in Project.Domain since ApplicationDbContext contains static constructor which set ApplicationDbInitializer, but then it turned out that Project.Domain and Project.WebUI have cyclic dependence, so I decided not move it and set database initializer in Global.asax.cs from Project.WebUI.

Then problems began. For some reasons method ApplicationDbInitializer.Seed isn't working and role "Admin" isn't created. Then I decided to try enable migrations. I enabled migrations in Project.Domain (as described here) and for implementing Seed I need access to classes from IdentityConfig.cs (ApplicationUserManager and ApplicationRoleManager) from Project.WebUI. Unfortunately, It again will create cyclic dependence.

My question is what to do: How properly to divide solution on projects and locate Identity 2.0 files? And why Seed method from ApplicationDbInitilizer not working?

Community
  • 1
  • 1
baira
  • 59
  • 2
  • 11

1 Answers1

0

I think we're trying to do exactly the same thing Sleepy, and I'm in the same boat as you. I'll fill you in with what I tried.

First off, you can fix the cyclic dependence by moving the ApplicationDbInitializer to the Application_Start method and calling Database.SetInitializer.

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
    }

This lets you keep the ApplicationDbContext and the ApplicationUser in the Domain, while leaving the ApplicationDbInitializer in the WebUI project.

Second, I had read a previous post that said to not use the GetOwinContext methods to get the userManager and the roleManager, but not sure how good of an idea that is. But at least that let's me get one step further.

Moving Identity 2.0 functions to repository class

    public static void InitializeIdentityForEf(ApplicationDbContext context) {
        // var userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
        // var roleManager = HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>();

        // Since we needed to move this class into the Domain namespace, we have to do the Owin differently

        var roleStore = new RoleStore<IdentityRole>(context);
        var roleManager = new RoleManager<IdentityRole>(roleStore);
        var userStore = new UserStore<ApplicationUser>(context);
        var userManager = new UserManager<ApplicationUser>(userStore);

The seed isn't populating when I do 'Update-Database', but it does try to run when I run the website and attempt to register a user. But I get an error

Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.

on this line

var result = await UserManager.CreateAsync(user, model.Password);
Community
  • 1
  • 1
Phillip Davis
  • 315
  • 3
  • 15