UnitOfWork in WCF with Quartz (Threads)

I have a question regarding a UoW template with SimpleInjector or any other IoC card. It should be noted that I already read about this various threads in stackoverflow, namely these two threads: Mixed lifestyle for each thread and for a web request with a simple injector and How to configure Simple Injector to start background threads in ASP.NET MVC

I am developing a WCF service. The service is dependent on IUnitOfWork. I can simply register IUnitOfWork with the RegsiterPerWcfOperation extension in SimpleInjector. However, my WCF service also generates some new jobs (threads) from the Quartz Scheduler framework. One of these jobs also contains a dependency on my IUnitOfWork, so I cannot use RegsiterPerWcfOperation. I could do as one of the stackoverflow threads says and register my IUnitOfWork as follows:

ScopedLifestyle hybridLifestyle = Lifestyle.CreateHybrid(
    () => OperationContext.Current != null || HttpContext.Current != null,
    new WcfOperationLifestyle(),
    new LifetimeScopeLifestyle());

container.Register<IUnitOfWork, UnitOfWork<TEntities>>(hybridLifestyle);

First of all, I'm not sure that the null check on is OperationContext.Currentcorrect, since my WCF service does not start in AspNetCompatibilityModebecause of the NET.TCP bindings - so checking the null value on HttpContext.Currentwould not help me if I did not start my WCF service using AspNetCompatibilityMode = true?

, Quartz , factory, IJob, :

public class SimpleInjectorJobFactory : IJobFactory
{
    private static readonly ILog _log = 
        LogManager.GetLog(typeof(SimpleInjectorJobFactory));
    private readonly Container _container;

    public SimpleInjectorJobFactory(Container container) {
        _container = container;
    }

    public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) {
        IJobDetail jobDetail = bundle.JobDetail;
        Type jobType = jobDetail.JobType;

        try 
        {
            if (_log.IsDebugEnabled) {
                _log.Debug(string.Format("Producing Instance of job: {0}, class: {1}",
                    jobDetail.Key, jobType.FullName));
            }

            // Return job registrated in container
            return (IJob)_container.GetInstance(jobType);
        }
        catch (Exception ex)
        {
            _log.Error("Problem instantiating class", ex);
            throw new SchedulerException("Problem instantiating class", ex);
        }
    }

    public void ReturnJob(IJob job) { }
}

IJob :

public class MyJob : IJob
{
    private static readonly ILog _log = LogManager.GetLog(typeof(MyJob));
    private readonly IUnitOfWork _unitOfWork;

    public MyJob(IUnitOfWork unitOfWork) {
        _unitOfWork = unitOfWork;
    }

    public void Execute(IJobExecutionContext context) {
        try
        {
            _unitOfWork.GetSomeDate().... //PSEUDO
        }
        catch (Exception ex)
        {
            _log.Error("Could not execute " + context.JobDetail.JobType, ex);
        }
    }
}

, , :

try
{
    using (container.BeginLifetimeScope())
    {
        var uow = container.GetInstance<IUnitOfWork>();
        uow.GetSomeDate().... //PSEUDO
    }
}

IoC ? , . , , . , , .

+3
1

. :

var hybridLifestyle = Lifestyle.CreateHybrid(
    container.GetCurrentWcfOperationScope() != null,
    new WcfOperationLifestyle(),
    new LifetimeScopeLifestyle());

container.GetCurrentWcfOperationScope(), container.GetCurrentLifetimeScope(), , .

, Container MyJob ( ). -. IJob, :

// This class is part of your Composition Root
public class LifetimeScopeJobDecorator : IJob {
    private readonly IJob _decoratee;
    private readonly Container _container;

    public LifetimeScopeJobDecorator(IJob decoratee, Container container) {
        _decoratee = decoratee;
        _container = container;
    }

    public void Execute(IJobExecutionContext context) {
        using (_container.BeginLifetimeScope()) {
            _decoratee.Execute(context);
        }
    }
}

, SimpleInjectorJobFactory. - SimpleInjectorJobFactory.NewJob:

var job = (IJob)_container.GetInstance(jobType);
return new LifetimeScopeJobDecorator(job, _container);

, . :

Type[] jobTypes = /* fetch IJob implementations here */;

// Instead of calling jobTypes.ToList().ForEach(container.Register), we register the
// types as a collection of IJob types.
container.RegisterAll<IJob>(types);

// Here we register the decorator
container.RegisterDecorator(typeof(IJob), typeof(LifetimeScopeJobDecorator));

// We create a jobFactory delegate.
// we use Lazy<T> because at this stage in the application the container might not
// be fully initialized yet.
var jobs = new Lazy<IEnumerable<IJob>>(() => container.GetAllInstance<IJob>());
var jobIndexes = types.ToDictionary(t => t, t => types.IndexOf(t));
Func<Type, IJob> jobFactory = jobType => jobs.Value.ElementAt(jobIndexes[jobType]);

// And pass that job factory on to the SimpleInjectorJobFactory.
var factory = new SimpleInjectorJobFactory(jobFactory);

// Inside the SimpleInjectorJobFactory:
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
    // ...
    // replace "return (IJob)_container.GetInstance(jobType);" with:        
    return _jobFactory(jobType);
    // ...
}

, , , . , factory .

+3

All Articles