5

Simple InjectorをIoCコンテナーとして使用しており、次の手法を使用して、Webリクエストごとまたはスレッドごとの両方で一部のオブジェクトの「混合」ライフスタイルを登録できるようにしています。

interface IUnitOfWork { }
interface IWebUnitOfWork : IUnitOfWork { }
interface IThreadUnitOfWork : IUnitOfWork { }
class UnitOfWork : IWebUnitOfWork, IThreadUnitOfWork { }

container.RegisterPerWebRequest<IWebUnitOfWork, UnitOfWork>();
container.RegisterLifetimeScope<IThreadUnitOfWork, UnitOfWork>();
container.Register<IUnitOfWork>(() => container.GetInstance<UnitOfWork>());

// Register as hybrid PerWebRequest / PerLifetimeScope.
container.Register<UnitOfWork>(() =>
{
    if (HttpContext.Current != null)
        return container.GetInstance<IWebUnitOfWork>() as UnitOfWork;
    else
        return container.GetInstance<IThreadUnitOfWork>() as UnitOfWork;
});

私はこのソリューションに完全に満足しているわけではありません。各要件について、それを機能させるために追加の空のインターフェイスを定義し、それらが私の具象クラスによって参照されるようにする必要があります。

追加のインターフェイスを定義する代わりに、次の拡張メソッドを使用しない理由はありますか?これらのメソッドに問題がある場合、コンテナーの現在のインスタンスがIIS内で実行されていることを完全に確信して確立する他の方法はありますか?

public static void RegisterHybridLifestyle<TService, TImplementation>(
    this Container container)
    where TService : class
    where TImplementation : class, TService
{
    if (System.Web.Hosting.HostingEnvironment.ApplicationHost != null)
        container.RegisterPerWebRequest<TService, TImplementation>();
    else
        container.RegisterLifetimeScope<TService, TImplementation>();
}

public static void RegisterForLifestyle<TConcrete>(
    this Container container)
    where TConcrete : class
{
    if (HostingEnvironment.ApplicationHost != null)
        container.RegisterPerWebRequest<TConcrete>();
    else
        container.RegisterLifetimeScope<TConcrete>();
}

アップデート

上記の質問とそれに続く質問は、SimpleInjectorとハイブリッド登録の誤解に基づいていました。上記およびSOの他の場所で説明されている手法は、コンテナーがWeb要求とWeb要求のコンテキスト内で実行されていないバックグラウンドプロセスの両方の要求を処理できる場合に使用されます。私が達成しようとしているのは、Webリクエストとスレッドリクエストの両方に適したコンテナの構成に対応するための変数登録です。つまり、IIS内で機能し、Windowsサービス内で機能するようにコンテナーを構成する必要があります。両方に同時に対応できる動的登録は必要ありません。

この結果は次の拡張メソッドであり、ソリューションから「余分な」インターフェイスを削除しました:-)

public static void RegisterForScope<TService, TImplementation>(this Container container)
    where TService : class
    where TImplementation : class, TService
{
    if (System.Web.Hosting.HostingEnvironment.ApplicationHost != null)
        container.RegisterPerWebRequest<TService, TImplementation>();
    else
        container.RegisterLifetimeScope<TService, TImplementation>();
}

public static void RegisterForScope<TConcrete>(this Container container)
    where TConcrete : class
{
    if (System.Web.Hosting.HostingEnvironment.ApplicationHost != null)
        container.RegisterPerWebRequest<TConcrete>();
    else
        container.RegisterLifetimeScope<TConcrete>();
}
4

1 に答える 1

3

私はこの解決策に完全に満足しているわけではありません

はい、私はこれに同意します。正直なところ、このようなことをしなければならないことは、実際にはIMOを吸います。これがSimpleInjector2.0で修正された理由です。ライフスタイルの明確な概念が含まれており、Lifestyle.CreateHybridハイブリッドライフスタイルの登録をはるかに簡単にするメソッドが含まれます。

ただし、すべてを追加するハイブリッドライフスタイルは必要ないようです。ハイブリッドライフスタイルは、動的に(呼び出しGetInstance<T>ごとおよび注入ごとに)切り替えることができるライフスタイルですが、起動時に切り替える必要があるだけのようです。あなたが定義した拡張メソッドを使用しても害はRegisterHybridLifestyleないと思いますが、これは実際にはハイブリッドライフスタイルではなく(名前が少し誤解を招く可能性があります)、単に構成/展開スイッチであることに注意してください。

Simple Injector 2以降では、これがはるかに簡単になり、次のようなことができるようになります。

// Define a lifestyle once based on the deployment.
Container.Options.DefaultScopedLifestyle =
    Lifestyle.CreateHybrid(
        lifestyleSelector: HostingEnvironment.ApplicationHost != null,
        trueLifestyle: new WebRequestLifestyle(),
        falseLifestyle: new LifetimeScopeLifestyle());

// And use it for registering the unit of work
// (no extra interfaces needed anymore).
container.Register<IUnitOfWork, UnitOfWork>(Lifestyle.Scoped);

// After setting DefaultScopedLifestyle, you can usr Lifestyle.Scoped
container.RegisterCollection(
    typeof(ISubscriber<>),
    new [] { typeof(ISubscriber<>).Assembly },
    Lifestyle.Scoped);
于 2013-02-04T17:59:52.760 に答える