用于多项目的AUTOFAC范围配置



我有一个ASP.NET Web应用程序,到目前为止,该应用程序一直在使用AutoFac配置类,该类已指定了应用程序中的InstancePerRequest()

从那以后,我在同一解决方案中创建了一个新的控制台应用程序,该应用程序将负责运行自动化的作业过程。由于我无法为控制台应用程序使用InstancePerRequest配置,因此我需要更改我的配置。理想情况下,我不想将所有配置复制到我的JobRunner应用程序中,并在那里使用" InstancePerLifetimeScope()"配置。

是否有更好的解决方案,我可以在很大程度上使用相同的配置来服务这两个项目?也许有一种方法可以覆盖我的Job Runner应用程序的配置,但不必为每个服务指定范围的更改?

尽管InstancePerLifetimeScopeInstancePerRequest通常具有相同的bahviour,但它们肯定具有不同的意图。我会避免使用InstancePerLifetimeScope作为置换式替换,因为很容易创建意外的副作用。例如,如果您有一项您打算在Web请求期间仅居住的服务,并且突然间,它在您的应用过程中生存(因为它无意中从根范围内解决)。

在您的工作跑步者内部,这种效果会更糟,尤其是如果您不创建自己的终生范围 - 在这种情况下, everythert everyther 将生活在根范围内,这意味着一个工作将会与对其有依赖的其他所有工作共享服务实例。

在封面下,InstancePerRequest()实际上只是将寿命范围标签(您可以从MatchingScopeLifetimeTags.RequestLifetimeScopeTag获得)委派给InstancePerMatchingLifetimeScope()。因此,您可以提出的一种方法是您可以切入中间人...例如,您可以更改AutoFac模块以将终身范围标签作为构造函数参数:

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

现在,当您从网络构建容器时,您需要提供众所周知的终身范围标签:

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

最新更新