3

インターフェイスにラップされたEFを使用してDbContext、Webリクエストごとに依存性を注入し、リクエスト全体が同じコンテキストを処理するようにします。また、認証サービスをカスタマイズRoleProviderするためにbyインターフェースを使用するカスタムもあります。DbContext

これまで、サービスロケーターパターンを使用してDbContext、カスタムRoleProviderの引数なしコンストラクターでインスタンスを解決してきました。は単調であるため、これによりいくつかの小さな問題が発生しました。そのため、無期限RoleProviderに保持される可能性がDbContextありますが、他の要求では、の間にそれを破棄する必要がありApplication_EndRequestます。

ウィンザーとは異なるiocコンテナーを使用していますが、これに基づくソリューションがあります。DIを使用して、RoleProviderhttpリクエストごとにカスタムインスタンスを作成できます。

私の質問は、私がすべきですか?

オープンにDbContextぶら下がっているのRoleProviderは無駄に思えます。一方、私はすべてのMVCAuthorizeAttributeがヒットすることを知っているのでRoleProvider(null以外のプロパティがある場合、ほとんどの場合そうです)、すでに待機Rolesしていると便利だと思います。DbContext

別の方法は、 Webリクエストごとではないものに別DbContextのものを注入することです。RoleProviderこのようにDbContextして、Webリクエストに対してのみ存在するは、シングルトニーに影響を与えることなく、最後に破棄できRoleProviderます。

どちらのアプローチが優れていますか、そしてその理由は何ですか?

コメント後に更新

スティーブン、これは本質的に私がしたことです。唯一の違いは、に依存しないことSystem.Web.Mvc.DependencyResolverです。代わりに、私は基本的に自分のプロジェクトにまったく同じものを持っていますが、名前が異なります。

public interface IInjectDependencies
{
    object GetService(Type serviceType);
    IEnumerable<object> GetServices(Type serviceType);
}

public class DependencyInjector
{
    public static void SetInjector(IInjectDependencies injector)
    {
        // ...
    }

    public static IInjectDependencies Current
    {
        get
        {
           // ...
        }
    }
}

これらのクラスはプロジェクトのコアAPIの一部であり、MVCとは異なるプロジェクトにあります。System.Web.Mvcこのように、他のプロジェクト(およびドメインプロジェクト)は、そのプロジェクトに対してコンパイルするために依存関係をとる必要はありませんDependencyResolver

そのフレームワークを考えると、UnityをSimpleInjectorと交換することはこれまでのところ簡単です。多目的シングルトンRoleProviderセットアップは次のようになります。

public class InjectedRoleProvider : RoleProvider
{
    private static IInjectDependencies Injector 
        { get { return DependencyInjector.Current; } }

    private static RoleProvider Provider 
        { get { return Injector.GetService<RoleProvider>(); } }

    private static T WithProvider<T>(Func<RoleProvider, T> f)
    {
        return f(Provider);
    }

    private static void WithProvider(Action<RoleProvider> f)
    {
        f(Provider);
    }

    public override string[] GetRolesForUser(string username)
    {
        return WithProvider(p => p.GetRolesForUser(username));
    }

    // rest of RoleProvider overrides invoke WithProvider(lambda)
}

Web.config:

<roleManager enabled="true" defaultProvider="InjectedRoleProvider">
    <providers>
        <clear />
        <add name="InjectedRoleProvider" type="MyApp.InjectedRoleProvider" />
    </providers>
</roleManager>

IoCコンテナ:

Container.RegisterPerWebRequest<RoleProvider, CustomRoleProvider>();

CUDに関しては、私の実装されているメソッドは1つだけCustomRoleProviderです。

public override string[] GetRolesForUser(string userName)

これはMVC AuthorizeAttribute(およびIPrincipal.IsInRole)で使用される唯一のメソッドであり、他のすべてのメソッドから、私は単に

throw new NotSupportedException("Only GetRolesForUser is implemented.");

プロバイダーにはCUDopsの役割がないため、トランザクションについては心配していません。

4

1 に答える 1

3

Griffin.MvcContribプロジェクトを見てください。これには、MVCを利用する実装が含まMembershipProviderれています。RoleProviderDependencyResolver

RoleProvider次のように構成できます。

<roleManager enabled="true" defaultProvider="MvcRoleManager">
  <providers>
    <clear />
    <add name="MvcRoleManager" 
      type="Griffin.MvcContrib.Providers.Roles.RoleProvider, Griffin.MvcContrib"
    />
  </providers>
</roleManager>

System.Web.MVCクラスを利用するため、使用しているDIコンテナーの実装DependencyResolverを構成する必要があります。IDependencyResolverSimple Injector(およびSimpleInjector.MVC3統合NuGetパッケージApplication_Start)では、イベントで次の構成が必要です。

container.RegisterAsMvcDependencyResolver();

は、同じアセンブリで定義されてGriffin.MvcContrib.Providers.Roles.RoleProviderいるに依存します。IRoleRepository完全なロールプロバイダーを実装する代わりに、を実装IRoleRepositoryしてコンテナーに登録するだけで済みます。

container.Register<IRoleRepository, MyOwnRoleRepository>();

このプロジェクトは、NuGetで見つけることができます。

アップデート

そして今、質問に答えましょう:

Griffin.MvcContrib RoleProviderはシングルトンになり、質問はIRoleRepositoryとその依存関係に移動しますが、質問は実際に残っています。

ロールプロバイダーから読み取るだけの場合(データベースを更新しないでください)。DbContextその場合、スレッドで同じものを再利用しない限り、どのライフタイムを選択してもかまいません。

ただし、ロールプロバイダーを使用してデータベースを更新すると、状況が異なります。その場合、私はそれに独自のコンテキストを与え、各操作の後に明示的にコミットさせます。そうしないと、誰がそれらの変更をコミットするのでしょうか?コマンドハンドラー(特にTransactionCommandHandlerDecorator)のコンテキストで実行する場合、操作はコマンドが成功した後にコミットされ、コマンドが失敗したときにロールバックされます。おそらく、コマンドが失敗したときにその変更をロールバックするのは問題ありません。しかし、役割プロバイダーがコマンドハンドラーのコンテキスト外で実行される場合、誰がそれをコミットするのでしょうか。あなたはこれを解決できると確信していますが、あなたは理解しにくいシステムになってしまい、それらの変更がコミットされなかった理由を見つけようとする他の開発者を驚かせるでしょう。

于 2012-03-23T07:22:53.813 に答える