我正在使用与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();
}
}
我有几个问题:
在观看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是一个处理传入作业的控制台应用程序。一项工作必须处理几个单位。为此,每个Job都使用一个具体的服务实现,但因为服务只是为了处理一个单元。当然我可以在JobController中做类似的事情。
foreach(var unit in unitsToProcess)
{
_service.DoSomethingWithUnit(unit);
}
但我想并行处理几个单位。这就是为什么我认为我需要几个具体服务的实例。
答案 0 :(得分:3)
我会做这样的事情
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以创建实际服务