Search code examples
c#sql-serverentity-frameworkasp.net-mvc-4simplemembership

MVC 4 SimpleMembership Model first


I have researched for the last couple days on Stack and other coding sites and cant seem to find a fix for my problem.

My goal is to configure simplemembership with my own database.(yes i have done a search and none of them answer my question)

I'm using visual studio 2013 and entity framework 4

I used the internet application template for asp.net mvc 4, that has already built in login.

I do as everyone else on line has done and seems to work for some, but most of the time they are left with no answer at all.

when i run my code and set the break points in the SimpleMembershipInitializer class. When I run it and click on register or login I step through the code and when it gets down to

WebSecurity.InitializeDatabaseConnection("AdventureWorksEntities", "mvcUser", "userID", "userName", autoCreateTables: false);

I get this error: "No user table found that has the name \"mvcUser\"."

what I know:

  • I know there is a table named "mvcUser"
  • I can CRUD the table and attribute in the table with in the site

If you want screen shots or more code please let me know.

Here is something similar to what I am looking/talking about but I don't understand what is meant by number 2 and 3 in the selected answer.

Controller

  [Authorize]
  [InitializeSimpleMembership]
  public class AccountController : Controller
  {

    private AdventureWorksEntities db = new AdventureWorksEntities();

This is at the top ^^

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public ActionResult Register(RegisterModel model)
    {
        if (ModelState.IsValid)
        {
            // Attempt to register the user
            try
            {
                WebSecurity.CreateUserAndAccount(model.userName, model.UserPassword);
                WebSecurity.Login(model.userName, model.UserPassword);
                return RedirectToAction("Index", "Home");
            }
            catch (MembershipCreateUserException e)
            {
                ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
            }
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

Model

public class UsersContext : DbContext
{
    public UsersContext()
        : base("AdventureWorksEntities")
    {
    }

    public DbSet<UserProfile> UserProfiles { get; set; }
}

Web.config

 <connectionStrings>    
 <add name="AdventureWorksEntities" connectionString="metadata=res://*/Models.AdventureworksContext.csdl|res://*/Models.AdventureworksContext.ssdl|res://*/Models.AdventureworksContext.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=LEMN-476W-IT;initial catalog=AdventureWorks;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
 </connectionStrings>

Filter\InitializerSimpleMembership.cs

private class SimpleMembershipInitializer
    {
        public SimpleMembershipInitializer()
        {
            Database.SetInitializer<UsersContext>(null);

            try
            {
                using (var context = new UsersContext())
                {
                    if (!context.Database.Exists())
                    {
                        // Create the SimpleMembership database without Entity Framework migration schema
                        ((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
                    }
                }

                WebSecurity.InitializeDatabaseConnection("AdventureWorksEntities", "mvcUser", "userID", "userName", autoCreateTables: false);
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex);
            }
        }
    }

Solution

  • "No user table found that has the name XXXXX" means that you can't use Entity Framework connection string (EntityClient provider) to initialize database connection for SimpleMembershipProvider, it must be initialized with a plain SqlClient provider connection string.

    There are 2 solutions to solve this problem:

    Single Connection String (EDM Only)

    Use EntityConnectionStringBuilder instance to generate SqlClient provider connection string, then point InitializeDatabaseConnection to use generated connection string:

    private class SimpleMembershipInitializer 
    {
        public SimpleMembershipInitializer() 
        {
            // initializer settings here
    
            var connectionBuilder = new EntityConnectionStringBuilder("AdventureWorksEntities");
            string sqlConnectionString = connectionBuilder.ConnectionString;
    
            WebSecurity.InitializeDatabaseConnection(sqlConnectionString, "mvcUser", "userID", "userName", autoCreateTables: false);
        }
    }
    

    Dual Connection String

    Add a new element on connectionStrings part in web.config file which includes SqlClient provider, so that it will looks like this (one for SQL Server & another one for EF):

    <connectionStrings>
       <add name="AdventureWorksDatabase" connectionString="Data Source=LEMN-476W-IT;Initial Catalog=AdventureWorks;Integrated Security=True" providerName="System.Data.SqlClient" />
       <add name="AdventureWorksEntities" connectionString="metadata=res://*/Models.AdventureworksContext.csdl|res://*/Models.AdventureworksContext.ssdl|res://*/Models.AdventureworksContext.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=LEMN-476W-IT;initial catalog=AdventureWorks;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
    </connectionStrings>
    

    Then, set InitializeDatabaseConnection to use newly created connection string:

    private class SimpleMembershipInitializer 
    {
        public SimpleMembershipInitializer() 
        {
            // initializer settings here
    
            WebSecurity.InitializeDatabaseConnection("AdventureWorksDatabase", "mvcUser", "userID", "userName", autoCreateTables: false);
        }
    }
    

    NB: The accepted answer from this post mentions how to convert Code First to Model First with SimpleMembershipProvider, but here you have Model First setup from start.

    Related issues:

    Can SimpleMembership and Entity Framework share a connection string?

    Setup a valid connection string for SimpleMembership