Question

How do you design your code-first approach in entity framework when your code should include user data (name, password...) without repeating/overwriting what the MVC framework will generate in terms of user tables, classes, authorization and authentication

As simple example, if i have an application that will manage user projects, my models will contain the following classes, and have the following relationship:

- One user may be assigned one or MANY projects
- One project may be assigned to one or MANY users

( just to show the many to many ERD relationship nature)

class User{
    //implementation of the class members and 
    // navigation properties to alow Entity Framework to create the DB tables
}

class Project{
    //implementation of the class members and 
    // navigation properties to alow Entity Framework to create the DB tables
}

Now the problem i am facing is that EF and ASP .net MVC framework takes care of creating user tables, profiles and roles entities...

I am not sure whether it is possible to design my classes in a way to show an automatic (conventional) relationship with the rest of the tables created by MVC.

In the case this needs to be done by writting custom Authentication classes, can you please explain how? because i have found many articles that discuss the same issue but without pointing out the relationship between the project classes and the MVC created classes / tables, plus if the developer choses to use the MVC way he will end up with two data contexts, even after merging both tables in one sql server catalog.

Was it helpful?

Solution

If I'm reading your question correctly, then what you're looking for is SimpleMembership.

Here's an explanation of SimpleMembership; from the section Easy to with[sic] Entity Framework Code First:

SimpleMembership ... allows[changed] you to use any table as a user store. That means you're in control of the user profile information, and you can access it however you'd like ....

So you can define your own User class to hold extra user data and relationships, e.g.:

[Table("UserProfile")]
public class UserProfile
{
    // required fields:
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int      UserId { get; set; }
    public string   UserName { get; set; }

    // your extra fields:
    public List<Project> Projects { get; set; }
    // more here...
}

and the regular, built-in Membership stuff is used for handling logins, passwords, and everything else behind the scenes.

There's a little more to be done to integrate it, but it wasn't too bad when I used it.

Note that this works from MVC4 on.


Edit to address questions asked in the comments:

From what I can tell looking at my code (it's been a while since I worked on the project and, between it being my first MVC project and other projects scrambling my brain since then, things are a bit fuzzy):

It looks like I ended up creating my own context that inherited from the DbContext class (as outlined in this tutorial) and contained all my application data; e.g.:

public class MyContext : DbContext
{
    public MyContext()
        : base("DefaultConnection")
    {

    }

    public DbSet<UserProfile> UserProfiles { get; set; }
    public DbSet<Projects> Projects { get; set; }
    // more here
}

(IIRC, by inheriting from the DbContext type we get all the built-in membership stuff.)

Then the rest of the app had to be configured to use this context (as given in the tutorial). (All of my controllers create an instance of my derived context, but this could be set up using dependency injection as well.)

It looks like the database connection is initialized in the InitializeSimpleMembershipAttribute by default -- this attribute gets applied to all the controllers.

I ran into the issue stated in this question with this setup, so to fix it I followed the advice in the accepted answer and moved the database connection initialization code to a central point (Global.asax.cs) that ran only once when the web app started.

I'm afraid that I can't remember many more details than this, so you'll probably have to do a bit more research (and probably troubleshooting) to get this working, but it should give you a decent idea of what to look for.

I ended up reading a lot of tutorials on asp.net, so you might check that site out if you've not already.

OTHER TIPS

Here is how you can accomplish this.

I am going to explain a way in which you can utilize existed Asp.Net Mvc Accounts Tables even plus you can add further into them as well as per your requirements.

First you need to install following Packages.

Install-Package Microsoft.AspNet.Identity
  Install-Package Microsoft.AspNet.Identity.EntityFramework

Now you would have to do further as follows.

First Of All Asp.Net Identity provides a table IdentityUser which contains following properties

Id,UserName,PasswordHash,SecurityStamp,Discriminator

Suppose I want to add further properties to i can do that by Creating a class and Inheriting it from IdentityUser

Here is example lets say I call it Client.

public class Client:IdentityUser
{

      //Suppose I want to add Further Properties to to my IdentityUser 
      //table provided by Asp.Net by default.
      //suppose i want Email,Date Birth.

   [Required]
   [Display(Name = "Email")]
   public string Email { get; set; }

   [Required]
   [Display(Name = "BirthDate")]
   public DateTime BirthDate { get; set; }

}


Now Create Your Model classes Lets say in my case One User can have many Projects.



 public class Project
  {


 //Now all your properties will go here
   // plus now you can connect projects to IdentityUser
   //by using Client class which is inherited from IdentityUser.

        public virtual Client Client{get; set;}

   }

Your further model classes will go here.

public class  SecondModelClass
   {

   }


Now Go to your context rather than inheriting it from DbContext you can inherit it from  IdentityDbContext   here is sample code below.

//Notice I am passing it Client class which was inherited from IdentityUser

public class YourContextName:IdentityDbContext<Client>
{


    public YourContextName():base("connectionStringName")
    {


    }


    public class IdentityUserLoginConfiguration :      EntityTypeConfiguration<IdentityUserLogin>
    {
        public IdentityUserLoginConfiguration()
        {
            HasKey(iul => iul.UserId);
        }
    }


    public class IdentityUserRoleConfiguration : EntityTypeConfiguration<IdentityUserRole>
    {
        public IdentityUserRoleConfiguration()
        {
            HasKey(iur => iur.RoleId);
        }

    }



    public DbSet<Project> Projects { get; set; }

    public DbSet<ModelClass2> AnyName { get; set; }

    public DbSet<ModelClass3> MoreClassesName { get; set; }




    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new IdentityUserLoginConfiguration());
        modelBuilder.Configurations.Add(new IdentityUserRoleConfiguration());
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

    }





}

Now it you entire AccountController you would have to pass your Client class inherited from IdentityUser

public class AccountController : Controller
{
    public AccountController()
        : this(new UserManager<Client>(new UserStore<Client>(new Context.YourContextName())))
    {
    }

    public AccountController(UserManager<Client> userManager)
    {
        UserManager = userManager;
    }

    public UserManager<Client> UserManager { get; private set; }


  //Further Code Will go below here........................
  //

}

This solution will utilize everything provided by Asp.Net Identity plus Your customization as well.

Cheers.

Licensed under: CC-BY-SA with attribution
scroll top