2012-09-25 45 views
24

可以SimpleMembership使用EF模型优先?当我尝试它时,当我拨打WebSecurity.InitializeDatabaseConnection.使用SimpleMembership与EF模型优先

时,我收到“无法找到请求的.NET Framework数据提供程序”:换句话说:当连接字符串使用了连接字符串时,我无法调用WebSecurity.InitializeDatabaseConnectionSystem.Data.EntityClient提供者(与使用模型优先范例时一样)。

要与你有模型的第一 User类摄制的问题,创建一个MVC 4应用程序,并更换代码优先用户配置实体类(你获得自由与MVC 4模板)在实体设计创建:

  1. 创建一个MVC 4应用程序VS 2012,并添加一个新的空白实体数据模型 。
  2. 将一个新的实体名为User添加到模型中,字段为Id, UserName, and FullName。所以,在这一点上,User数据实体是 映射到Users表,并通过时髦的连接访问 字符串,它使用System.Data.EntityClient提供程序。
  3. 验证EF可以访问User实体。执行 的一种简单方法是根据用户表 及其关联的DbContext脚架出用户控制器。
  4. 编辑AccountModels.cs文件删除UserProfile类和 其关联的UsersContext类。将对 (现在缺失)UserProfileUsersContext类的引用替换为您的新用户类及其关联的DbContext类的引用 。
  5. 将调用InitializeDatabaseConnection从 InitializeSimpleMembershipAttribute过滤器类移到Global.asax.cs中的 Application_Start方法。当您在此时, 修改参数以使用您的新用户实体的连接 字符串,表名和UserId列名称。
  6. 删除(不再使用)InitializeSimpleMembershipAttribute 类及其引用。

当你运行摄制,它会在呼叫得到异常InitializeDatabaseConnection.

鲍勃

+1

你的意思是替换public DbSet UserProfiles {get;组; }(public DbSet userProfiles {get; set;})。我对此有所修正 –

+1

@PeterEdike是的,这就是我想要做的。我尝试用我的模型优先的东西来替换所有代码优先的东西,但是我发现SimpleMembership不适用于连接字符串中的模型优先。正如Mario Zderic所说,解决方案是使用看起来像代码优先的连接字符串。 –

回答

24

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

1. InitializeSimpleMembershipAttribute.cs从MVC 4互联网应用templete应该是这样的

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

3。修复AccountCotroler.cs与您的模型一的DbContext(ExternalLoginConfirmation(RegisterExternalLoginModel model, string returnUrl)法)

4.Define您"ConnStringForWebSecurity"连接字符串这是不一样的时髦康恩字符串模型的第一DB访问,请注意,我们使用的供应商System.Data.SqlClientSystem.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> 
+2

谢谢马里奥!这引发了一些关于两个DbContext连接如何相互协作的问题。我将为这两个问题创建新的论坛主题。 –

+2

双连接字符串是我在DbFirst中丢失的部分!因此,重要的SimpleMembershipProvider助手只能使用传统的连接字符串而不是EF连接字符串。 – profMamba

+1

我是新来的MVC世界,现在我有同样的问题...,你在第2,3点的意思,请你能提前向我这样的新手们提供一个更好的解释。 –

12

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

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

[Authorize(Roles="Sales")] 

..然后你会作为过滤器检查用户的角色,但供应商AREN有一个例外没有初始化。

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

+0

谢谢克雷格。当我第一次着手将我的模型优先实体与SimpleMembership魔法融合在一起时,实际上我已经移除了ISMA,并将调用从InitializeDatabaseConnection从惰性初始化程序移至Global.asax.cs中的Application_Start方法。我只是不想在这个细节的原始发布中复杂化这个场景。 每当我尝试将我的模型优先实体绑定到SimpleMembership时,无论是在懒惰初始化程序中还是在Application_Start中进行调用,都会发生“找不到提供程序”异常。 –

+1

是的,有30行负面代码的解决方案!我喜欢。 +1 –

10

1 - 你需要启用迁移,prefereably用的EntityFramework 5

2 - 将您

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

在你YourMvcApp /迁移/ Configuration.cs类的种子法

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来仅将SimpleMembershipProvider注册到已创建的UserProfile表中(对于您的情况,您可以用您的定制表名称替换“UserProfile”参数值),同时也提供SimpleMembershipProvider的哪一列是UserId和UserName。我还展示了如何添加用户,角色并将您的Seed方法中的两者与自定义UserProfile属性/字段关联的示例,例如用户的手机(号码)。

3 - 现在当你从包管理器控制台运行更新的数据库,EF5将提供与您的所有自定义属性

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

+0

感谢龙乐。不幸的是,我的问题是我使用“模型优先”,而不是“代码优先”。据我所知(纠正我,如果我错了),“迁移”功能只适用于代码优先,而不是模型优先。但是一旦我获得了基本的claptrap工作,创建角色和用户的代码示例将非常有用! - 鲍勃 –

+1

Bob.as.SBS - 我很高兴至少在我的回答中有些东西对你有帮助,你是否介意提起这个问题,因为它对你有一些帮助? - 谢谢 – LeLong37

+0

如果我可以的话。我没有足够的“声誉”投票。 –

0

我无法与EF和WebMatrix web安全类一起使用,以避免此问题并继续:

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

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

在我的情况下,模型的连接字符串,数据和网络是不同的proyects所以对我来说是不是从web.project的web.config中删除此信息的问题。

现在websecuroty.initializedatabase不能与EF连接字符串一起运行。

我希望这可以帮助

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时无处不在。但是当你使用依赖注入模式时,这不是一个大问题。