【问题标题】:SimpleInjector mixed lifestyle for per web request and lifetime scope针对每个 Web 请求和生命周期范围的 SimpleInjector 混合生活方式
【发布时间】:2013-02-04 13:10:27
【问题描述】:

我使用 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>();
}

更新

上面的问题and this follow on question是基于对SimpleInjector和混合注册的误解。上面和 SO 其他地方描述的技术适用于容器可以为 Web 请求和不在 Web 请求上下文中运行的后台进程的请求提供服务的情况。我一直在尝试实现的是变量注册,以适应适用于 Web 请求 OR 线程请求的容器配置。即我需要将我的容器配置为在 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>();
}

【问题讨论】:

    标签: c# .net dependency-injection simple-injector


    【解决方案1】:

    我对这个解决方案并不完全满意

    是的,我同意这一点。老实说,不得不做这样的事情实际上很糟糕 IMO。这就是在 Simple Injector 2.0 中修复此问题的原因。它包含生活方式的明确概念,并将包含一个Lifestyle.CreateHybrid 方法,这使得注册混合生活方式变得更加容易。

    但是,您似乎不需要混合生活方式。混合生活方式是一种可以动态切换的生活方式(每次调用GetInstance&lt;T&gt; 和每次注射),而您似乎只需要在启动期间进行切换。我认为使用您定义的 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);
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多