gpt4 book ai didi

multithreading - WCF 中的 UnitOfWork 与 Quartz(线程)

转载 作者:行者123 更新时间:2023-12-04 06:47:51 27 4
gpt4 key购买 nike

我对使用 SimpleInjector 或任何其他 IoC 框架的 UoW 模式有疑问。应该注意的是,我已经在 stackoverflow 上阅读了有关它的各种线程,更具体地说,这两个线程:Mixed lifestyle for Per Thread and Per Web Request with Simple InjectorHow to configure Simple Injector to run background threads in ASP.NET MVC

我正在开发 WCF 服务。该服务依赖于 IUnitOfWork。我可以在 SimpleInjector 中使用 RegsiterPerWcfOperation 扩展注册 IUnitOfWork。但是,我的 WCF 服务还从 Quartz 调度程序框架中生成了一些新作业(线程)。其中一项工作还包含对我的 IUnitOfWork 的依赖,因此我无法使用 RegsiterPerWcfOperation。我可以像其中一个 stackoverflow 线程所说的那样做,并像这样注册我的 IUnitOfWork:

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

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

首先,我不确定 OperationContext.Current 的 null 检查是否正确,因为我的 WCF 服务没有在 AspNetCompatibilityMode 中运行,因为 NET .TCP 绑定(bind) - 所以对 HttpContext.Current 的空检查对我没有帮助,除非我使用 AspNetCompatibilityMode = true 运行我的 WCF 服务?

好的,所以我的 Quartz 依赖项已在容器中注册,并且我已经创建了一个工厂,因此框架可以像这样创建我的 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 框架紧密耦合吗?我似乎找不到合适的方法来解决这个问题。我已经阅读了一些关于装饰器的内容,但是我似乎无法弄清楚如何使用它们。我希望我能得到一个很好的例子,说明我如何解决我的问题。

最佳答案

你快到了。您需要创造以下混合生活方式:

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

您需要调用 container.GetCurrentWcfOperationScope()container.GetCurrentLifetimeScope() 来确定选择哪种生活方式。

此外,您应该绝对避免在您的MyJob(或任何作业实现)中引用Container。那是 an anti-pattern .相反,您应该创建一个 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);

让 Simple Injector 为您进行装饰会更漂亮,但在您的情况下这将是更多的代码。方法如下:

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);
// ...
}

最后一个解决方案更复杂,但是当您有多个装饰器时,这种方法会变得非常有趣,尤其是当它们需要根据实现类型有条件地应用时。这样工厂就不需要知道任何有关应用的装饰器的信息。

关于multithreading - WCF 中的 UnitOfWork 与 Quartz(线程),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21879646/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com