I am working on project with a very similar approach like the one in this post. I am using Unity as DI-Framework and I am very new to that. There is a JobController which should start an injected service n times in a new Task. The code looks pretty much the same as in Chads initial post.
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();
});
}
}
}
As my concrete services aren't thread safe, I followed Marks approach and implemented a decorator which needs a factory for each concrete service like the example in Marks answer. My classes looks like that:
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();
}
}
I have several problems with that:
- The code isn't DRY. I don't want to code a ThreadSafeService-Decorator for each of my services. And also I don't want to have a new ServiceFactory for each of my services.
- The implementation of my ServiceFactories have to know how to create the concrete services, but as these services are stored as internal classes in another assembly and also have other dependencies (to repositories etc.) which have to be injected, I am not sure where to place the factories and how to create the concrete services with all their dependencies by using Unity.
After watching Marks video I tried to solve the first issue by implementing an interceptor for Unity like the following:
internal class ThreadSafeServiceInterceptor : IInterceptionBehavior
{
IServiceFactory serviceFactory;
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
serviceFactory.Create().Start();
return getNext()(input, getNext);
}
...
}
The serviceFactory is injected via constructor. Apart from the fact that I still haven't found a good solution for issue 2, how can I tell Unity which concrete SessionFactory has to be injected to my interceptor? It depends on the service which is started. At the moment in my application I do something like that:
var service = container.Resolve<IService>("Service1");
var controller = container.Resolve<JobController>(new ParameterOverride("service", service));
controller.StartWork();
But of course the service can't be resolved. Unity isn't able to inject the serviceFactory as there are several registrations for IServiceFactory (for each of my services). In addition to that my interceptor would create a new service instance and start it. After that, when calling getNext()(), the resolved service starts too and do the same things. But as there could be other interceptors I have to call getNext().
All that lets me think that I am not on the right way. As I have learned, the interceptors should handle cross-cutting concerns. But making a service multi-threaded isn't a cross-cutting concern, right?
Perhaps someone can point me into the right direction?
UPDATE
@oleksii: Yes and no. It is a real world project but I am still drafting the architecture. For that I want to have a small protoype and check it against the requirements. I do have several services which can be consumed via different UIs. In this case the UI is a console application which processes incoming Jobs. One job has to process several units. To do that each Job consumes a concrete service-implementation but as the services are designed to process just one unit. Of course I can do something like that in my JobController.
foreach(var unit in unitsToProcess)
{
_service.DoSomethingWithUnit(unit);
}
But I want to process several units parallel. This is why I think I need several instances of my concrete service.