虽然InstancePerLifetimeScope
并且InstancePerRequest
经常有相同的行为,但他们肯定有不同的意图。我会避免InstancePerLifetimeScope
用作替代品,因为它很容易产生意想不到的副作用。例如,如果您有一个服务,您原本打算只在 Web 请求期间存在,但突然之间,它会在您的应用程序期间存在(因为它无意中从根范围解析)。
这种效果在您的作业运行器中会更糟,特别是如果您没有创建自己的生命周期范围 - 在这种情况下,所有内容都将存在于根范围内,这意味着一个作业将与其他所有作业共享服务实例这对它有依赖性。
在幕后,实际上只是使用众所周知的生命周期范围标记(您可以从中获得)InstancePerRequest()
委托给。所以,你可以实现你所要求的一种方法是你可以切断中间人......例如,你可以更改你的 Autofac 模块以将生命周期范围标记作为构造函数参数:InstancePerMatchingLifetimeScope()
MatchingScopeLifetimeTags.RequestLifetimeScopeTag
internal class MyModule : Module
{
private string _lifetimeScopeTag;
public MyModule(string lifetimeScopeTag)
{
_lifetimeScopeTag = lifetimeScopeTag;
}
protected override void Load(ContainerBuilder builder)
{
builder.RegisterAssemblyTypes()
// equivalent to: .InstancePerRequest()
.InstancePerMatchingLifetimeScope(_lifetimeScopeTag);
}
}
现在,当您从 Web 构建容器时,您需要提供众所周知的生命周期范围标记:
internal static class WebIoC
{
public static IContainer BuildContainer()
{
var lifetimeScopeTag = MatchingScopeLifetimeTags.RequestLifetimeScopeTag;
var builder = new ContainerBuilder();
builder.RegisterModule(new MyModule(lifetimeScopeTag));
return builder.Build();
}
}
对于您的工作执行者,您现在可以使用您自己的终身范围标签来模仿这种行为!
internal static class JobRunnerIoC
{
public const string LifetimeScopeTag = "I_Love_Lamp";
public static IContainer BuildContainer()
{
var builder = new ContainerBuilder();
builder.RegisterModule(new MyModule(LifetimeScopeTag));
// Don't forget to register your jobs!
builder.RegisterType<SomeJob>().AsSelf().As<IJob>();
builder.RegisterType<SomeOtherJob>().AsSelf().As<IJob>();
return builder.Build();
}
}
(我在这里假设您的每个作业都实现了一个接口,假设它看起来像这样):
public interface IJob
{
Task Run();
}
现在你只需要在它们自己的生命周期范围内运行这些作业,使用你刚刚制作的标签,例如:
public class JobRunner
{
public static void Main(string[] args)
{
var container = JobRunnerIoC.BuildContainer();
// Find out all types that are registered as an IJob
var jobTypes = container.ComponentRegistry.Registrations
.Where(registration => typeof(IJob).IsAssignableFrom(registration.Activator.LimitType))
.Select(registration => registration.Activator.LimitType)
.ToArray();
// Run each job in its own lifetime scope
var jobTasks = jobTypes
.Select(async jobType =>
{
using (var scope = container.BeginLifetimeScope(JobRunnerIoC.LifetimeScopeTag))
{
var job = scope.Resolve(jobType) as IJob;
await job.Run();
}
});
await Task.WhenAll(jobTasks);
}
}