web-dev-qa-db-ja.com

SimpleMembershipをEFモデルファーストで使用する

SimpleMembershipEF model-firstと一緒に使用できますか?試してみると、WebSecurity.InitializeDatabaseConnection.を呼び出すと、「要求された.NET Frameworkデータプロバイダーが見つかりません」と表示されます。

別の言い方をすると、接続文字列がWebSecurity.InitializeDatabaseConnectionプロバイダーを使用している場合、System.Data.EntityClientへの呼び出しが機能しません(model-firstを使用する場合のように)パラダイム)。

問題を再現するには、MVC 4アプリを作成し、code-first UserProfileエンティティークラス(MVC 4テンプレートで無料で入手できます)をmodel-firstに置き換えます。 =エンティティデザイナーで作成したユーザークラス:

  1. VS 2012でMVC 4アプリを作成し、新しい空のエンティティデータモデルを追加します。
  2. Id,UserName, and FullNameのフィールドを使用して、Userという名前の新しいエンティティをモデルに追加します。したがって、この時点で、UserデータエンティティはUsersテーブルにマップされ、System.Data.EntityClientプロバイダーを使用するファンキーな接続文字列を介してアクセスされます。
  3. [〜#〜] ef [〜#〜]Userエンティティにアクセスできることを確認します。これを行う簡単な方法の1つは、Userテーブルとそれに関連付けられたDbContextに基づいて、Usersコントローラーをスキャフォールドすることです。
  4. AccountModels.csファイルを編集して、UserProfileクラスとそれに関連するUsersContextクラスを削除します。 (現在欠落している)UserProfileおよびUsersContextクラスへの参照を、新しいUserクラスおよび関連するDbContextクラスへの参照に置き換えます。
  5. InitializeDatabaseConnectionの呼び出しを、InitializeSimpleMembershipAttributeフィルタークラスからGlobal.asax.csのApplication_Startメソッドに移動します。その間、引数を変更して、新しいUserエンティティの接続文字列、テーブル名、およびUserId列名を使用します。
  6. (もう使用されない)InitializeSimpleMembershipAttributeクラスとその参照を削除します。

リプロを実行すると、InitializeDatabaseConnection.の呼び出し時にExceptionが取得されます

ボブ

24

SimpleMembershipは最初にモデルを操作できます。これが解決策です。

1 ._InitializeSimpleMembershipAttribute.cs_ MVC 4インターネットアプリケーションのテンプレートは次のようになります。

_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. _AccountCotroler.cs_を修正して、モデルファーストDbContext(ExternalLoginConfirmation(RegisterExternalLoginModel model, string returnUrl)メソッド)で動作するようにします。

4.モデルファーストデータベースアクセス用のファンキーなconn文字列とは異なる_"ConnStringForWebSecurity"_接続文字列を定義します。プロバイダーは_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>
_
24
Mario Zderic

これはMVC 4のバグです このブログ投稿には回避策があります

アクションフィルターとして、InitializeSimpleMembershipAttributeOnActionExecutingにフックして遅延初期化作業を実行しますが、これはライフサイクルの後半では遅すぎる可能性があります。 Authorize属性は、ロールベースのアクセスチェック(OnAuthorization中)を実行する必要がある場合、プロバイダーを早期に準備する必要があります。つまり、サイトへの最初のリクエストが次のようなコントローラーアクションにヒットした場合:

[Authorize(Roles="Sales")]

..すると、フィルターがユーザーの役割をチェックするがプロバイダーは初期化されないため、例外が発生します。

私の推奨は、プロジェクトからISMAを削除し、アプリケーション開始イベント中にWebSecurityを初期化することです。

12
Craig Stuntz

1-できればEntityFramework 5で移行を有効にする必要があります

2-移動

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

your 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を呼び出して、SimpleMembershipProviderを既に作成されているUserProfileテーブルに登録するだけです(この場合、 「UserProfile」パラメータ値とカスタムテーブル名)。ま​​た、SimpleMembershipProviderに、どの列がUserIdとUserNameであるかを伝えます。また、ユーザー、ロールを追加する方法の例と、2つをSeedメソッドをユーザーのモバイル(番号)などのカスタムUserProfileプロパティ/フィールドに関連付ける)に関連付けています。

3-パッケージマネージャーコンソールからupdate-databaseを実行すると、EF5はテーブルにすべてのカスタムプロパティをプロビジョニングします

追加の参照については、ソースコードとともにこの記事を参照してください:http://blog.longle.net/2012/09/25/seeding-users-and-roles-with- mvc4-simplemembershipprovider-simpleroleprovider-ef5-codefirst-and-custom-user-properties /

10
LeLong37

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構成で単一の接続文字列を使用できますが、データコンテキストでデフォルトコンストラクターを使用できない1つの問題です。代わりに、データコンテキストをインスタンス化するときにどこにでも接続文字列名をシードする必要があります。しかし、依存関係注入パターンを使用する場合、それは大きな問題ではありません。

1
ktutnik

この問題を回避して先に進むために、EFおよびWebMatrix webSecurityクラスを操作することはできません。

Efモデルを最初にコードに変更します。

接続文字列を変更して、providerName = "System.Data.SqlClient"(すべてのメタデータ情報を削除)を使用するか、EF接続を使用します。

私の場合、モデル、データ、Webは異なるプロジェクトであるため、web.projectのweb.configからこの情報を削除しても問題はありません。

現在、websecuroty.initializedatabaseはEF接続文字列で実行されません。

これが役に立てば幸い

0
jlsfernandez