请看一下 Quartz.Unity nuget 包https://github.com/hbiarge/Quartz.Unity,这个统一包有一个不错的 ScopedLifetime 实现。
除了上面的 nuget 包之外,如果你使用多个统一容器实例并将生命周期管理器作为委托传递,它将允许你正确处理每个石英作业以及每个 http 请求的一次性类型,例如 DBContext .
您必须为 asp.net mvc / web api 设置一个单独的 IUnityContainer 实例,并为 Quartz 调度程序设置另一个 IUnityContainer 实例。
这是一个完整的工作示例
https://github.com/vinodres/DITestingWithQuartz
如果您查看 QuartzStartup.cs,我已经使用它来初始化 Quartz Scheduler。为简单起见,假设 IHelloService 是一次性类型,它必须在每个作业结束以及每个 http 请求结束时被释放。在这里,我正在创建一个单独的实例
IUnityContainer 分配给 QuartzContainer 并从 Quartz.Unity nuget 包中添加了名为 QuartzUnityExtention 的新扩展。还调用了我在另一个名为 unityconfig.cs 的文件中创建的 .Configure 扩展方法。该方法以 Func 为参数。该参数允许您根据执行路径传递不同的生命周期管理器实例。
这里是 QuartzStartup.cs
[assembly: OwinStartup(typeof(DiTestingApp.QuartzStartup))]
namespace DiTestingApp
{
/// <summary>
///
/// </summary>
public class QuartzStartup
{
private static readonly ILog Log = LogManager.GetLogger(typeof(QuartzStartup));
/// <summary>
/// Get the hangfire container.
/// </summary>
private static readonly Lazy<IUnityContainer> QuartzContainer = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
container.AddNewExtension<QuartzUnityExtension>();
container.Configure(() => new HierarchicalLifetimeManager());
return container;
});
/// <summary>
///
/// </summary>
/// <param name="app"></param>
public void Configuration(IAppBuilder app)
{
Log.Info("Quartz Startup Intitializing...");
var container = QuartzContainer.Value;
InitScheduler(container);
Log.Info("Quartz Startup Intialization Complete...");
var properties = new AppProperties(app.Properties);
var cancellationToken = properties.OnAppDisposing;
if (cancellationToken != CancellationToken.None)
{
cancellationToken.Register(() =>
{
QuartzContainer.Value.Dispose();
Log.Info("Quartz container disposed (app pool shutdown).");
});
}
}
private void InitScheduler(IUnityContainer container)
{
try
{
var scheduler = container.Resolve<IScheduler>();
scheduler.Start();
IJobDetail job = JobBuilder.Create<HelloWorldJob>().Build();
ITrigger trigger = TriggerBuilder.Create()
.WithSimpleSchedule(x => x.WithIntervalInSeconds(20).RepeatForever())
.Build();
scheduler.ScheduleJob(job, trigger);
}
catch (Exception ex)
{
Log.Error(ex);
}
}
}
}
我对 asp.net mvc / web api 依赖解析器配置进行了类似的设置。我创建了一个名为 UnityMvcActivator.cs 的文件,在这里当我调用 .Configure 扩展方法时,我正在传递 PerRequestLifetimeManager。
UnityMvcActivator.cs
using System;
using System.Linq;
using System.Web.Http;
using System.Web.Mvc;
using Common.Logging;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Mvc;
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(DiTestingApp.App_Start.UnityWebActivator), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(DiTestingApp.App_Start.UnityWebActivator), "Shutdown")]
namespace DiTestingApp.App_Start
{
/// <summary>Provides the bootstrapping for integrating Unity with ASP.NET MVC.</summary>
public static class UnityWebActivator
{
private static readonly ILog Log = LogManager.GetLogger(typeof(UnityWebActivator));
/// <summary>
/// Get the hangfire container.
/// </summary>
private static readonly Lazy<IUnityContainer> WebContainer = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
container.Configure(() => new PerRequestLifetimeManager());
return container;
});
/// <summary>Integrates Unity when the application starts.</summary>
public static void Start()
{
Log.Info("Web api DI container intializing.");
var container = WebContainer.Value;
FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
// TODO: Uncomment if you want to use PerRequestLifetimeManager
Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
var resolver = new Microsoft.Practices.Unity.WebApi.UnityDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
Log.Info("Web api DI container intialization complete.");
}
/// <summary>Disposes the Unity container when the application is shut down.</summary>
public static void Shutdown()
{
Log.Info("Web api DI container disposing.");
var container = WebContainer.Value;
container.Dispose();
}
}
}
现在是使用 IUnityContainer 注册类型的部分。这是 UnityConfig.cs 中配置方法的实现。在这里,我注册了 IHelloService 以使用disposableLifetimeManager 委托。调用委托时,会根据您的执行路径提供适当的生命周期管理器。如果在 asp.net mvc / web api 的上下文中使用 IHelloService,它将是 PerRequestLifetimeManager。如果在 Quartz Job 中使用,它将是 HierarchicalLifetimeManager。
UnityConfig.cs
using System;
using DiTestingApp.Models;
using Microsoft.Practices.Unity;
using Quartz;
using Testing.Scheduler;
namespace DiTestingApp
{
/// <summary>
/// Specifies the Unity configuration for the main container.
/// </summary>
public static class UnityConfig
{
/// <summary>
///
/// </summary>
/// <param name="container"></param>
/// <param name="disposableLifetimeManager"></param>
/// <returns></returns>
public static IUnityContainer Configure(this IUnityContainer container, Func<LifetimeManager> disposableLifetimeManager )
{
container.RegisterType<IJob, HelloWorldJob>();
container.RegisterType<IHelloService, HelloService>(disposableLifetimeManager());
return container;
}
}
}
HierarchicalLifetimeManager 用于 Quartz 执行路径,因此任何一次性类型都将在每个作业结束时正确处置。
如果 Quartz.Unity 实现不足以满足您的用例,您可以随时对其进行进一步定制。