多项目解决方案的Autofac范围配置

问题描述 投票:0回答:1

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

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

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

c# asp.net-mvc dependency-injection autofac autofac-configuration
1个回答
2
投票

虽然InstancePerLifetimeScopeInstancePerRequest经常拥有相同的行为,但他们肯定有不同的意图。我会避免使用InstancePerLifetimeScope作为替代品,因为它很容易产生意想不到的副作用。例如,如果您有一项服务,您打算仅在Web请求期间生存,并且突然它在您的应用程序期间存在(因为它无意中从根范围解析)。

在你的求职者中,这种影响会更糟,特别是如果你没有创建自己的生命周期范围 - 在这种情况下,一切都将存在于根范围内,这意味着一个作业将与其他所有工作共享服务实例它依赖于它。

在封面下,InstancePerRequest()实际上只是委托给InstancePerMatchingLifetimeScope()一个着名的终身范围标签(你可以从MatchingScopeLifetimeTags.RequestLifetimeScopeTag获得)。所以,你可以实现你所要求的一种方法是你可以切断中间人......例如,你可以改变你的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);
    }    
}

现在,当您从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);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.