2012-09-25 51 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時無處不在。但是當你使用依賴注入模式時,這不是一個大問題。