Using SimpleMembership with EF model-first

后端 未结 5 1843
孤城傲影
孤城傲影 2020-12-02 19:15

Can SimpleMembership be used with EF model-first? When I try it, I get \"Unable to find the requested .NET Framework Data Provider\" when

相关标签:
5条回答
  • 2020-12-02 19:34

    1 - You need to enable migrations, prefereably with EntityFramework 5

    2 - Move your

    WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "EmailAddress", autoCreateTables: true); 
    

    to your Seed method in your YourMvcApp/Migrations/Configuration.cs class

        protected override void Seed(UsersContext context)
        {
            WebSecurity.InitializeDatabaseConnection(
                "DefaultConnection",
                "UserProfile",
                "UserId",
                "UserName", autoCreateTables: true);
    
            if (!Roles.RoleExists("Administrator"))
                Roles.CreateRole("Administrator");
    
            if (!WebSecurity.UserExists("lelong37"))
                WebSecurity.CreateUserAndAccount(
                    "lelong37",
                    "password",
                    new {Mobile = "+19725000000", IsSmsVerified = false});
    
            if (!Roles.GetRolesForUser("lelong37").Contains("Administrator"))
                Roles.AddUsersToRoles(new[] {"lelong37"}, new[] {"Administrator"});
        }
    

    Now EF5 will be in charge of creating your UserProfile table, after doing so you will call the WebSecurity.InitializeDatabaseConnection to only register SimpleMembershipProvider with the already created UserProfile table (In your case, you can replace the "UserProfile" parameter value with your custom table name), also tellling SimpleMembershipProvider which column is the UserId and UserName. I am also showing an example of how you can add Users, Roles and associating the two in your Seed method with custom UserProfile properties/fields e.g. a user's Mobile (number).

    3 - Now when you run update-database from Package Manager Console, EF5 will provision your table with all your custom properties

    For additional references please refer to this article with sourcecode: http://blog.longle.net/2012/09/25/seeding-users-and-roles-with-mvc4-simplemembershipprovider-simpleroleprovider-ef5-codefirst-and-custom-user-properties/

    0 讨论(0)
  • 2020-12-02 19:39

    I´m not able to work with EF and WebMatrix webSecurity class so to avoid this problem and go ahead:

    Change my Ef model first to code first.

    Change the connection string to use providerName="System.Data.SqlClient"(removing all the metadata information) or use the EF connection

    In my case the model, data and web are different proyects so for me is not an issue to remove this information from the web.config on the web.project.

    Nowadays websecuroty.initializedatabase dosen't run with EF connection string.

    I wish this helps

    0 讨论(0)
  • 2020-12-02 19:41

    SimpleMembership can work with model first. Here is the solution.

    1.InitializeSimpleMembershipAttribute.cs from MVC 4 Internet Application templete should look like this

    namespace WebAndAPILayer.Filters
    {
        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
        public sealed class InitializeSimpleMembershipAttribute : ActionFilterAttribute
        {
            private static SimpleMembershipInitializer _initializer;
            private static object _initializerLock = new object();
            private static bool _isInitialized;
    
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                // Ensure ASP.NET Simple Membership is initialized only once per app start
                LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
            }
    
            private class SimpleMembershipInitializer
            {
                public SimpleMembershipInitializer()
                {
                    try
                    {
                        WebSecurity.InitializeDatabaseConnection("ConnStringForWebSecurity", "UserProfile", "Id", "UserName", autoCreateTables: true);
                    }
                    catch (Exception ex)
                    {
                        throw new InvalidOperationException("Something is wrong", ex);
                    }
                }
            }
        }
    }
    

    2.Delete CodeFirst Classes from AcountModel.cs

    3.Fix AccountCotroler.cs to work with your Model-first DbContext (ExternalLoginConfirmation(RegisterExternalLoginModel model, string returnUrl) method)

    4.Define your "ConnStringForWebSecurity" connection string which is not same as that funky conn string for model-first db access, notice that we use provider System.Data.SqlClient not System.Data.EntityClient

     <connectionStrings>
             <add name="ModelFirstEntityFramework" connectionString="metadata=res://*/Context.csdl|res://*/Context.ssdl|res://*/Context.msl;provider=System.Data.SqlClient;provider
     connection string=&quot;data source=.\SQLEXPRESS;Initial
     Catalog=aspnet-MVC4;Integrated
     Security=SSPI;multipleactiveresultsets=True;App=EntityFramework&quot;"
     providerName="System.Data.EntityClient" />
             <add name="ConnStringForWebSecurity" connectionString="data source=.\SQLEXPRESS;Initial Catalog=aspnet-MVC4;Integrated
     Security=SSPI" providerName="System.Data.SqlClient" />
           </connectionStrings>
    
    0 讨论(0)
  • 2020-12-02 19:47

    this problem caused by WebSecurity.InitializeDatabaseConnection can't use connection string with System.Data.EntityClient provider name.

    providing dual connection string isn't sound good, so you can generate the connection string for EF model first in the constructor in the partial class.

    the code is look like bellow

    public partial class MyDataContext 
    {
        private static string GenerateConnectionString(string connectionString)
        {
            var cs = System.Configuration.ConfigurationManager
                         .ConnectionStrings[connectionString];
    
            SqlConnectionStringBuilder sb = 
                 new SqlConnectionStringBuilder(cs.ConnectionString);
            EntityConnectionStringBuilder builder = 
                 new EntityConnectionStringBuilder();
            builder.Provider = cs.ProviderName;
            builder.ProviderConnectionString = sb.ConnectionString;
            builder.Metadata = "res://*/MyDataContext.csdl|" +
                  "res://*/MyDataContext.ssdl|res://*/MyDataContext.msl";
            return builder.ToString();
        }
    
        public MyDataContext(string connectionName) : 
              base(GenerateConnectionString(connectionName)) { }
    }
    

    with this trick you can use single connection string on your web config, but one problem you can't use default constructor on your datacontext, instead you should seed connection string name everywhere when you instantiate the datacontext. but it is not a big problem when you use dependency injection pattern.

    0 讨论(0)
  • 2020-12-02 19:49

    That's a bug in MVC 4. There's a workaround in this blog post.

    As an action filter, InitializeSimpleMembershipAttribute hooks into OnActionExecuting to perform the lazy initialization work, but this can be too late in the life cycle. The Authorize attribute will need the providers to be ready earlier if it needs to perform role based access checks (during OnAuthorization). In other words, if the first request to a site hits a controller action like the following:

    [Authorize(Roles="Sales")]
    

    .. then you’ll have an exception as the filter checks the user’s role but the providers aren’t initialized.

    My recommendation is to remove ISMA from the project, and initialize WebSecurity during the application start event.

    0 讨论(0)
提交回复
热议问题