Instantiating an object in a worker thread with Dependency Injection

扶醉桌前 提交于 2019-12-12 13:14:54

问题


My objective is to run a never ending process in a parallel thread. The problem is, I cannot just instantiate my worker service in the new Thread, because I am using DI in my application.

Based on my research here on SO, I have noticed many people are suggesting that Abstract Factories need to be injected into the thread to dynamically instantiate a thread-safe object in a parallel thread. 1, 2

/// <summary>
/// Responsible for starting parallel long running worker threads
/// </summary>
public class ParallelWorkerStarter
{
    private readonly IQueueProcessorFactory _queueProcessorFactory;

    public ParallelWorkerStarter(IQueueProcessorFactory queueProcessorFactory)
    {
        _queueProcessorFactory = queueProcessorFactory;
    }

    public void StartQueueProcessorThread()
    {    
        queueProcessor = new Thread(
        () =>
        {
            _queueProcessorFactory.Create().ProcessQueue();
        })
        { Name = "QueueProcessor" };
        queueProcessor.Start();
    }
}

The Abstract Factory for IQueueProcessorFactory looks like this:

/// <summary>
/// Abstract factory responsible for producing an <see cref="IQueueProcessor"/>
/// </summary>
/// <remarks>
///  This abstract factory is used to generate an <see cref="IQueueProcessor"/> In a seperate thread. 
///  Therefore, all of its dependencies also need to be dynamically generated
/// </remarks>
public interface IQueueProcessorFactory
{
    /// <summary>
    /// Dynamically creates ab <see cref="IQueueProcessor"/>
    /// </summary>
    /// <returns>
    /// The <see cref="IQueueProcessor"/>.
    /// </returns>
    IQueueProcessor Create();
}

Now, my main problem is, the concrete QueueProcessor that implements IQueueProcessor has 11 dependencies (I'm aware of the SRP code smell), and each dependency has 5-6 dependencies itself.

/// <inheritdoc />
public class QueueProcessorFactory : IQueueProcessorFactory
{
    private readonly IEventTriggerQueuedEventServiceFactory _qeueuedEventServiceFactory;

    private readonly ILoggerFactory _loggerFactory;

    private readonly IEventTriggerActionGroupLogServiceFactory _eventTriggerActionGroupLogServiceFactory;

    private readonly IExceptionLogServiceFactory _exceptionLogServiceFactory;

    private readonly IEventTriggerServiceFactory _eventTriggerServiceFactory;

    private readonly IConditionServiceFactory _conditionServiceFactory;

    private readonly IEventTriggerActionServiceFactory _eventTriggerActionServiceFactory;

    private readonly IEngineEnabledCheckerFactory _engineEnabledCheckerFactory;

    private readonly IEventTriggerScheduleSetServiceFactory _eventTriggerScheduleSetServiceFactory;

    private readonly IEventTriggerActionResultServiceFactory _eventTriggerActionResultServiceFactory;

    private readonly IWorkflowExceptionHandlerFactory _workflowExceptionHandlerFactory;

    public QueueProcessorFactory(
        IEventTriggerQueuedEventServiceFactory qeueuedEventServiceFactory,
        ILoggerFactory loggerFactory,
        IEventTriggerActionGroupLogServiceFactory eventTriggerActionGroupLogServiceFactory,
        IExceptionLogServiceFactory exceptionLogServiceFactory,
        IEventTriggerServiceFactory eventTriggerServiceFactory,
        IConditionServiceFactory conditionServiceFactory,
        IEventTriggerActionServiceFactory eventTriggerActionServiceFactory,
        IEngineEnabledCheckerFactory engineEnabledCheckerFactory,
        IEventTriggerScheduleSetServiceFactory eventTriggerScheduleSetServiceFactory,
        IEventTriggerActionResultServiceFactory eventTriggerActionResultServiceFactory,
        IWorkflowExceptionHandlerFactory workflowExceptionHandlerFactory)
    {
        _qeueuedEventServiceFactory = qeueuedEventServiceFactory;
        _loggerFactory = loggerFactory;
        _eventTriggerActionGroupLogServiceFactory = eventTriggerActionGroupLogServiceFactory;
        _exceptionLogServiceFactory = exceptionLogServiceFactory;
        _eventTriggerServiceFactory = eventTriggerServiceFactory;
        _conditionServiceFactory = conditionServiceFactory;
        _eventTriggerActionServiceFactory = eventTriggerActionServiceFactory;
        _engineEnabledCheckerFactory = engineEnabledCheckerFactory;
        _eventTriggerScheduleSetServiceFactory = eventTriggerScheduleSetServiceFactory;
        _eventTriggerActionResultServiceFactory = eventTriggerActionResultServiceFactory;
        _workflowExceptionHandlerFactory = workflowExceptionHandlerFactory;
    }

    /// <inheritdoc />
    public IQueueProcessor Create()
    {
        return new QueueProcessor(
            _qeueuedEventServiceFactory.Create(),
            _loggerFactory.Create(),
            _eventTriggerActionGroupLogServiceFactory.Create(),
            _exceptionLogServiceFactory.Create(),
            _eventTriggerServiceFactory.Create(),
            _conditionServiceFactory.Create(),
            _eventTriggerActionServiceFactory.Create(),
            _engineEnabledCheckerFactory.Create(),
            _eventTriggerScheduleSetServiceFactory.Create(),
            _eventTriggerActionResultServiceFactory.Create(),
            _workflowExceptionHandlerFactory.Create());
    }
}

Does this mean I need ~60+ abstract factories in order to instantiate my IQueueProcessor in a worker thread? This sounds like a nightmare! Is there a better way or a more efficient way to achieve this?


回答1:


Does this mean I need ~60+ abstract factories in order to instantiate my IQueueProcessor in a worker thread?

In the worst case, that may be required. This can happen when all dependencies must have Transient lifetime - for example when they aren't thread-safe.

In the best case, however, all those dependencies could have Singleton lifetime, which could be appropriate for thread-safe dependencies. In that case, no internal factories are required:

public class QueueProcessorFactory : IQueueProcessorFactory
{
    private readonly IEventTriggerQueuedEventService _qeueuedEventService;    
    private readonly ILogger _logger;    
    private readonly IEventTriggerActionGroupLogService _eventTriggerActionGroupLogService;
    // etc...

    public QueueProcessorFactory(
        IEventTriggerQueuedEventService qeueuedEventService,
        ILogger logger,
        IEventTriggerActionGroupLogService eventTriggerActionGroupLogService,
        /* etc... */)
    {
        _qeueuedEventService = qeueuedEventService;
        _logger = logger;
        _eventTriggerActionGroupLogService = eventTriggerActionGroupLogService;
        // etc...
    }

    public IQueueProcessor Create()
    {
        return new QueueProcessor(
            _qeueuedEventService,
            _logger,
            _eventTriggerActionGroupLogService,
            /* etc... */);
    }
}

In reality, you may need to mix some Transient dependencies (that'd require factories) with some Singleton dependencies.

If you ultimately require dozens of factories, you could consider using a DI Container. Some of them can automatically generate implementations of factory interfaces - you only have to supply the interface they must implement.

Additionally, you don't have to define an interface for each dependency, but could consider instead using a generic interface like:

public interface IFactory<T>
{
    T Create();
}

Again, some of the DI Containers out there support such factories. You could also consider entirely dispensing with an interface and just use a delegate like Func<T>.

Unless the circumstances are special, however, I don't recommend a DI Container, but rather endorse Pure DI. When you use a DI Container, you lose compile-time safety, which I tend to think isn't worth the trade-off; after all, the bottleneck of programming is rarely your typing speed.



来源:https://stackoverflow.com/questions/50137520/instantiating-an-object-in-a-worker-thread-with-dependency-injection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!