quj*_*jck 5 .net c# dependency-injection simple-injector
我使用 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;
});
Run Code Online (Sandbox Code Playgroud)
我对此解决方案并不完全满意,因为对于每个要求,我都必须定义额外的空接口才能使其工作并确保它们被我的具体类引用。
我是否有任何理由不应该使用以下扩展方法而不是定义额外的接口?如果这些方法存在一些问题,是否有其他方法可以完全放心地确定我当前的容器实例正在 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>();
}
Run Code Online (Sandbox Code Playgroud)
更新
上述问题和后续问题是基于对 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>();
}
Run Code Online (Sandbox Code Playgroud)
我对这个解决方案并不完全满意
是的,我同意这一点。老实说,在我看来,不得不做这样的事情实际上很糟糕。这就是 Simple Injector 2.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);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3486 次 |
最近记录: |