4

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.

6
  • You mean that if you modify the classes/tables generated for your template, those changes can't be saved or get lost? Commented Aug 29, 2014 at 17:35
  • @BartvanIngenSchenau. What i mean is, without repeating the creation of the users class and table, how can i tell EF and MVC framework, to create my entities and make some of them depend/use the user class automatically generated by the login process
    – joe
    Commented Aug 29, 2014 at 19:43
  • think of it this way: if you are not creating a new application but extending an existing one that already has a User class, how would you go about adding these new features? Commented Aug 30, 2014 at 6:26
  • @BartvanIngenSchenau, this is exactly what i am thinking, except that when i search the generated account controler...i do not find any "user" entity, plus, user and roles tables' fields are not related to any class members (the same way EF code-first works)
    – joe
    Commented Aug 30, 2014 at 14:14
  • The .NET framework calls its user class MembershipUser. You will probably need to extend that class and possibly implement a new MembershipProvider.
    – dartonw
    Commented Aug 30, 2014 at 14:59

2 Answers 2

2
+50

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.

2
  • thanks for the link, this looks exactly what i am looking for with one exception, i believe, i still need to deal with two separate data contexts, userscontext and the application context. but it's a great step, if you do not mind, since you've used it before, did you manage to get all your entities (app classes, and membership classes) using the same datacontext? for initialization and queries...? Thanks
    – joe
    Commented Sep 4, 2014 at 21:52
  • @joe I updated my answer to answer your questions -- there was too much for just a comment.
    – paul
    Commented Sep 5, 2014 at 13:26
2

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.

3
  • very detailed, thanks i will consider your approach.
    – joe
    Commented Sep 6, 2014 at 18:59
  • plz let me know if you found any issues in this i am willing to help you. Commented Sep 7, 2014 at 3:08
  • Hi joe have you solved your issue the way i suggested you above plz let me know Commented Sep 9, 2014 at 9:22

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.