twreynol
twreynol

Reputation: 269

mvc 4 simple membership asks to be initialized, even though it is

I have a custom table named Customer with CustomerId and Email as two fields (among others). I want to use this in an MVC4 site.
I have a single connection string with a name of DBRuWho. In my App_Start\AuthConfig.cs file, I have a method called CheckForSuperAdmin() which will seed my table with an initial superuser.

 internal static void CheckForSuperAdmin()
    {
        if (!WebMatrix.WebData.WebSecurity.Initialized)
        {
            WebMatrix.WebData.WebSecurity.InitializeDatabaseConnection("DBRuWho", "customer", "customerId", "email", true);
        }

        var roles = new WebMatrix.WebData.SimpleRoleProvider();
        var users = new WebMatrix.WebData.SimpleMembershipProvider();
        if (!roles.RoleExists("SuperAdmin"))
        {
            roles.CreateRole("SuperAdmin");
            if (users.GetUser("[email protected]", false) == null)
            {
                users.CreateUserAndAccount("[email protected]", "P@ssw0rd53cR3t!");
                roles.AddUsersToRoles(new[] {"[email protected]"}, new[] {"SuperAdmin"});
            }
        }
    }

When I "Register a user", a Customer Row gets created as does a row in the webpages_Membership table, and they both look good. However, I can only register a user if I set a breakpoint at the "var roles" line above and skip over the rest of the method.

Then, with this user created, I cannot login - I get a password mismatch.

If I do NOT skip over the code starting with "var roles", I get an exception that: You must call the "WebSecurity.InitializeDatabaseConnection" method before you call any other method of the "WebSecurity" class.

This is frustrating, as you can clearly see that I DO call that method. And after it is called, I look at it in my Watch window, and it states that it is initialized.

So, I am stuck here.... I would like to use this "Simple" membership, but it does not seem to allow me to use it simply!

Any thoughts? I read lots of articles and it sure seems like I am doing everything correctly, but obviously I am missing something here...

More Info: Here is my connection string that maps to DBRuWho.

 <connectionStrings>
<add name="DBRuWho" connectionString="Server=localhost;Database=ruwho;integrated security=true" providerName="System.Data.SqlClient" />

I am pretty sure I am connecting properly, because the data gets inserted! I just can't seem to get past the exception when I check for !roles.RoleExists and I cannot get logged in.

Update -- I deleted all data in my Customer table and all data in the webpages_Membership table, and now (if I skip over the !roles.RoleExists code while starting up), I CAN log in.
However, when I try to step through the roles code to create my super admin, I still get the exception that I noted above.

Upvotes: 0

Views: 1287

Answers (1)

twreynol
twreynol

Reputation: 269

Finally found the answer. It is in the way I was instancing up the providers. The proper way that works is:

public class Init
{
    const string SUPER_ADMIN_ROLE = "SuperAdmin";

    internal static void CheckForSuperAdmin()
    {
        if (!WebMatrix.WebData.WebSecurity.Initialized)
        {
            WebMatrix.WebData.WebSecurity.InitializeDatabaseConnection("DBRuWho", "customer", "customerId", "email", true);
        }
        var roles = (SimpleRoleProvider)Roles.Provider;
        var users = (SimpleMembershipProvider)Membership.Provider;
        if (!roles.RoleExists(SUPER_ADMIN_ROLE))
        {
            roles.CreateRole(SUPER_ADMIN_ROLE);
            string email = "[email protected]";
            string pswd = "P@ssw0rd!";
            string credentials = API.Helpers.Misc.CreateCompanyCredential(pswd);
            if (users.GetUser(email, false) == null)
            {
                Dictionary<string, object> args = new Dictionary<string, object>()
                {
                    {"Name", email},
                    {"CustomerToken", Guid.NewGuid()},
                    {"Credentials",  credentials},
                    {"isActive",   true}
                };

                users.CreateUserAndAccount(email, pswd, args);
                roles.AddUsersToRoles(new[] { email }, new[] { SUPER_ADMIN_ROLE });
            }
        }
    }
}

I found this on a somewhat related post here on S/O which I promptly lost the link to (oops!)

I included other attributes that I needed to send to my CUSTOMER class, just as an example for someone else's benefit. They are not necessarily required.

At any rate, I made three changes to get this to work.

1) Make sure you are using version 2.0 of Web.Matrix and Web.Matrix.data

2) I added the following to my web.config

<membership defaultProvider="SimpleMembershipProvider">
  <providers>
    <clear />
    <add name="SimpleMembershipProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
  </providers>
</membership>
<roleManager defaultProvider="SimpleRoleProvider" enabled="true">
  <providers>
    <clear />
    <add name="SimpleRoleProvider" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData" />
  </providers>
</roleManager>

3) I made the code change listed above.

I did these all in this order and after #3 it started working. Hooray! I am posting this in case some other poor unsuspecting soul tries to instance up new providers....

Upvotes: 1

Related Questions