Chr*_*ris 12 c# dependency-injection simple-injector
简单的注入器文档提供了有关如何为WebRequest,Web API,WCF设置容器的很好示例......但这些示例一次特定于一种技术/生活方式.我们的Web应用程序大部分使用它们!我不清楚如何配置容器以适应多种生活方式.
假设我有一个带有Web API的MVC项目.我有以下对象:
我应该为每种生活方式创建和配置一个容器吗?
当我注册的所有内容RegisterPerWebRequest<T>都适用于两种类型的控制器.这样安全吗?或者在Web API控制器中使用async/await时会遇到麻烦吗?
当我同时注入相同实例的MVC和Web API控制器时,最佳配置是什么?
我应该使用混合生活方式吗?
现在让事情变得复杂......我们的应用程序也使用后台任务和SignalR.
这些都有时会发生在WebRequest之外,并且需要访问如上所述的相同对象.
最好的解决方案是使用Lifetime范围?
我需要为这种生活方式创造一个新的容器吗?或者我可以重用/重新配置我的MVC/Web API容器吗?
有三重生活方式吗?
我不得不说,我在前一段时间遇到过类似的情况,最后我通过我的web API和signalR分享了我的配置,但你需要为signalR实现自定义的生活方式,因为它不是基于web请求.
特别是在signalR中,你会发现在Hub中处理每个web请求依赖项的一些问题,其中一些将像httpContext.Current一样是空的.
解决方案:
您需要WebRequestLifestlye与Lifestyle.Transient,Lifestyle.Singleton或LifetimeScopeLifestyle之间的混合生活方式.我最终完成了使用装饰模式,你可以阅读这篇文章和另一篇文章.
我的装饰师
public class CommandLifetimeScopeDecorator<T> : ICommandHandler<T>
{
private readonly Func<ICommandHandler<T>> _handlerFactory;
private readonly Container _container;
public CommandLifetimeScopeDecorator(
Func<ICommandHandler<T>> handlerFactory, Container container)
{
_handlerFactory = handlerFactory;
_container = container;
}
public void Handle(T command)
{
using (_container.BeginLifetimeScope())
{
var handler = _handlerFactory(); // resolve scoped dependencies
handler.Handle(command);
}
}
}
public interface ICommandHandler<in T>
{
void Handle(T command);
}
Run Code Online (Sandbox Code Playgroud)
我使用signalR的集线器激活器来管理依赖项
public class MyHubActivator : IHubActivator
{
private readonly Container _container;
public MyHubActivator(Container container)
{
_container = container;
}
public IHub Create(HubDescriptor descriptor)
{
return _container.GetInstance(descriptor.HubType) as IHub;
}
}
Run Code Online (Sandbox Code Playgroud)
复合根文件,您将在其中处理依赖项
public CompositRoot(Container container)
{
_container = container;
}
public container Configure()
{
// _container.Registerall container dependencies
return _container;
}
Run Code Online (Sandbox Code Playgroud)
然后在引导应用程序时共享复合根配置
var compositRoot = new CompositRoot(simpleInjector.Container); //simple injector instance
compositRoot.Configure();
Run Code Online (Sandbox Code Playgroud)
对于signalR
GlobalHost.DependencyResolver.Register(typeof(IHubActivator), () => new MyHubActivator(compositRoot));
Run Code Online (Sandbox Code Playgroud)
并且您可以在其他项目中重用您的配置!
我的两分钱希望有所帮助!
通常你不需要每个生活方式有一个容器; 通常,您希望每个AppDomain都有一个容器实例.然而,在与MVC相同的项目中混合Web API从架构的角度来看是一个可怕的想法IMO(如此处,此处和此处所述).因此,如果您将这些部分分离到自己的体系结构块中,那么您已经有了更少的问题.
但是如果您在同一个项目中运行MVC和Web API,这基本上意味着您将始终使用Web API.WebApiRequestLifestyle明确构建为工作:
在IIS的内部和外部.即它可以在没有HttpContext.Current的自托管Web API项目中运行.(来源)
在一般情况下,它是安全的,当你有没有打算利用旋转并行操作的使用,以防WebRequestLifestyle您只在IIS中运行ConfigureAwait(false)(这应该是真是难得IMO)作为解释在这里.
因此,如果您仍然在同一个项目中将Web API与MVC混合使用,则没有理由使用混合生活方式 ; 你可以简单地使用相同的生活方式.对于做后台处理你可能但是需要建立一个混合的生活方式,但它的每一个场景需要不同的混合.但是,混合动力车可以堆叠起来,如果需要,您可以轻松创建"三重生活方式".
由于您希望使用SignalR进行后台处理,因此您需要确定运行这些后台操作的范围生活方式.最明显的生活方式是LifetimeScopeLifestyle,这意味着您应该使用以下范围的生活方式进行范围注册:
var hybridLifestyle = Lifestyle.CreateHybrid(
lifestyleSelector: () => HttpContext.Current != null,
trueLifestyle: new WebRequestLifestyle(),
falseLifestyle: new LifetimeScopeLifestyle());
Run Code Online (Sandbox Code Playgroud)
但是,生命周期范围需要显式启动(如果在Web应用程序中包含SimpleInjector.Integration.Web.dll,则会为您隐式启动Web请求范围).如何做到这一点取决于你的设计,但这个关于SignalR的q/a可能会指出你正确的方向.
| 归档时间: |
|
| 查看次数: |
3972 次 |
| 最近记录: |