使用SimpleMembership和EF模型优先

时间:2012-09-25 02:07:13

标签: entity-framework simplemembership

SimpleMembership 可以与 EF型号优先一起使用吗?当我尝试它时,当我调用WebSecurity.InitializeDatabaseConnection.

时,我得到“无法找到所请求的.NET Framework数据提供程序”

换句话说:当连接字符串使用WebSecurity.InitializeDatabaseConnection提供程序时,我无法调用System.Data.EntityClient(就像使用 model-first <时一样) / strong>范例)。

要重新解决此问题,请创建一个MVC 4应用,并使用模型优先替换代码优先 UserProfile实体类(使用MVC 4模板免费获得) 您在实体设计器中创建的用户类:

  1. VS 2012 中创建MVC 4应用,并添加新的空白实体数据 模型。
  2. 向模型添加名为User的新实体,其中包含Id,的字段 UserName, and FullName。那么,此时,User数据实体就是 映射到Users表,可通过时髦的连接访问 使用System.Data.EntityClient提供程序的字符串。
  3. 验证 EF 是否可以访问User实体。一个简单的方法 那就是基于User表来构建一个Users控制器 及其相关的DbContext。
  4. 编辑AccountModels.cs文件以删除UserProfile类和 其关联的UsersContext类。替换对的引用 (现在缺少)带引用的UserProfileUsersContext类 到您的新用户类及其关联的DbContext类。
  5. 将调用移至InitializeDatabaseConnection InitializeSimpleMembershipAttribute过滤器类到 Global.asax.cs中的Application_Start方法。当你在它的时候, 修改参数以使用新用户实体的连接 字符串,表名和UserId列名。
  6. 删除(不再使用)InitializeSimpleMembershipAttribute 类及其引用。
  7. 当你运行repro时,在调用InitializeDatabaseConnection.

    时会出现异常

    鲍勃

5 个答案:

答案 0 :(得分:24)

SimpleMembership可以先使用模型。这是解决方案。

来自MVC 4 Internet Application模板的

1。InitializeSimpleMembershipAttribute.cs应如下所示

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.删除AcountModel.cs

中的CodeFirst类

3.Fix AccountCotroler.cs使用您的模型优先DbContext(ExternalLoginConfirmation(RegisterExternalLoginModel model, string returnUrl)方法)

4.定义您的"ConnStringForWebSecurity"连接字符串,该字符串与用于模型优先的数据库访问的那个时髦conn字符串不同,请注意我们使用提供程序System.Data.SqlClient而不是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>

答案 1 :(得分:12)

这是MVC 4中的一个错误。There's a workaround in this blog post

  

作为动作过滤器,InitializeSimpleMembershipAttribute挂钩到OnActionExecuting以执行延迟初始化工作,但这在生命周期中可能为时已晚。如果需要执行基于角色的访问检查(在OnAuthorization期间),Authorize属性将需要提供者提前准备好。换句话说,如果对站点的第一个请求命中控制器操作,如下所示:

[Authorize(Roles="Sales")]
  

..然后你会有一个例外,因为过滤器会检查用户的角色,但是提供程序没有初始化。

     

我的建议是从项目中删除ISMA,并在应用程序启动事件期间初始化WebSecurity。

答案 2 :(得分:10)

1 - 您需要启用迁移,特别是使用EntityFramework 5

2 - 移动你的

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

到YourMvcApp / Migrations / Configuration.cs类中的Seed方法

    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"});
    }

现在EF5将负责创建您的UserProfile表,在这样做之后,您将调用WebSecurity.InitializeDatabaseConnection以仅使用已创建的UserProfile表注册SimpleMembershipProvider(在您的情况下,您可以替换“UserProfile”带有自定义表名的参数值),也可以通过Tellling SimpleMembershipProvider列中的UserId和UserName。我还展示了如何添加用户,角色并将Seed方法中的两者与自定义UserProfile属性/字段相关联的示例,例如用户的手机(号码)。

3 - 现在,当您从Package Manager控制台运行update-database时,EF5将为您的表配置所有自定义属性

有关其他参考资料,请参阅本文的源代码: 的 http://blog.longle.net/2012/09/25/seeding-users-and-roles-with-mvc4-simplemembershipprovider-simpleroleprovider-ef5-codefirst-and-custom-user-properties/

答案 3 :(得分:1)

WebSecurity.InitializeDatabaseConnection引起的此问题无法将连接字符串与System.Data.EntityClient提供程序名称一起使用。

提供双连接字符串听起来不太好,因此您可以首先在分部类的构造函数中为EF模型生成连接字符串。

代码看起来像是吼叫

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)) { }
}

使用这个技巧你可以在你的web配置上使用单个连接字符串,但是你不能在datacontext上使用默认构造函数的一个问题,而是在实例化datacontext时你应该在任何地方设置连接字符串名称。但是当你使用依赖注入模式时,这不是一个大问题。

答案 4 :(得分:0)

我无法使用EF和WebMatrix webSecurity类,以避免此问题并继续:

首先将我的Ef模型更改为代码。

更改连接字符串以使用providerName =“System.Data.SqlClient”(删除所有元数据信息)或使用EF连接

在我的情况下,模型,数据和网络是不同的项目,因此对于我而言,从web.project上的web.config中删除此信息不是问题。

现在websecuroty.initializedatabase没有使用EF连接字符串运行。

我希望这有帮助