正确在多线程应用程序中使用IOC(装饰器还是拦截器?)
作者:互联网
我正在使用非常相似的方法(例如this post中的方法)来进行项目.我将Unity用作DI-Framework,对此我还很新.
有一个JobController应该在新Task中启动n次注入服务.该代码看起来与Chads初始帖子中的代码几乎相同.
public class Controller
{
IService _service;
public Controller(IService service)
{
this._service = service;
}
public Action DoSomethingManyTimes()
{
for(int i =0; i < numberOfTimes; i++)
{
Task.Factory.StartNew(() =>
{
_service.DoSomething();
});
}
}
}
由于我的具体服务不是线程安全的,因此我遵循Marks的方法并实现了一个装饰器,该装饰器需要一个工厂来为每个具体的服务提供服务,就像Marks答案中的示例一样.我的课看起来像这样:
public ThreadSafeService1 : IService
{
private readonly IServiceFactory factory;
public ThreadSafeService1(IServiceFactory factory)
{
this.factory = factory;
}
public void DoSomething()
{
this.factory.Create().DoSomething();
}
}
internal class Service1Factory : IServiceFactory
{
public IService Create()
{
return new Service1();
}
}
我有几个问题:
>代码不是DRY.我不想为我的每个服务编写ThreadSafeService-Decorator.而且我也不想为每个服务都拥有一个新的ServiceFactory.
>我的ServiceFactories的实现必须知道如何创建具体的服务,但是由于这些服务作为内部类存储在另一个程序集中,并且还具有必须注入的其他依赖项(对存储库等),因此我不确定在哪里使用Unity放置工厂以及如何创建具有所有依赖关系的具体服务.
看完Marks video之后,我尝试通过为Unity实现拦截器来解决第一个问题,如下所示:
internal class ThreadSafeServiceInterceptor : IInterceptionBehavior
{
IServiceFactory serviceFactory;
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
serviceFactory.Create().Start();
return getNext()(input, getNext);
}
...
}
serviceFactory是通过构造函数注入的.除了我仍然没有找到问题2的好的解决方案这一事实之外,我怎么能告诉Unity必须将哪个具体的SessionFactory注入到我的拦截器中?这取决于启动的服务.目前,在我的应用程序中,我会执行以下操作:
var service = container.Resolve<IService>("Service1");
var controller = container.Resolve<JobController>(new ParameterOverride("service", service));
controller.StartWork();
但是,当然服务无法解决. Unity无法注入serviceFactory,因为IServiceFactory有多个注册(针对我的每个服务).
除此之外,我的拦截器还将创建一个新的服务实例并启动它.之后,当调用getNext()()时,解析的服务也将启动并执行相同的操作.但是由于可能还有其他拦截器,我必须调用getNext().
所有这些让我觉得我走错了路.据我了解,拦截器应该处理跨领域的问题.但是使服务成为多线程不是跨领域的问题,对吗?
也许有人可以指出我正确的方向?
更新
@oleksii:
是的,没有.这是一个现实世界的项目,但我仍在起草体系结构.为此,我想要一个小的原型,并对照要求进行检查.我确实有几个服务,可以通过不同的UI来使用.
在这种情况下,UI是一个控制台应用程序,用于处理传入的作业.一项工作必须处理多个单元.为此,每个作业都会消耗一个具体的服务实现,但是由于服务被设计为仅处理一个单元.当然,我可以在JobController中执行类似的操作.
foreach(var unit in unitsToProcess)
{
_service.DoSomethingWithUnit(unit);
}
但是我想并行处理几个单元.这就是为什么我认为我需要几个具体服务实例的原因.
解决方法:
我会做这样的事情
public class Controller
{
Func<IService> _factory;
public Controller(Func<IService> factory)
{
_factory = factory;
}
public Action DoSomethingManyTimes()
{
for(int i =0; i < numberOfTimes; i++)
{
Task.Factory.StartNew(() =>
{
_factory().DoSomething();
});
}
}
}
任何体面的DI容器都应该知道如何解析Func(我不使用Unity,默认情况下autofac会这样做).因此,您为服务注入一个工厂,然后每个任务将具有自己的服务实例.
我通常在单例存储库中使用这种方法,在该存储库中注入DbConnection的工厂或任何我需要的东西,然后每种方法将在不同的实例上工作并且不共享任何状态.
更新资料
服务工厂可以是一个抽象工厂,因此每个服务没有一个工厂,而所有服务都有一个工厂.所以也许像这样
Func<string,IService>
然后,您将Unity设置为仅注入工厂方法(来自服务工厂类).该工厂可以封装Unity以创建实际的服务
标签:multithreading,dependency-injection,c,ioc-container 来源: https://codeday.me/bug/20191120/2046399.html