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

C# 多项目解决方案的Autofac范围配置,c#,asp.net-mvc,dependency-injection,autofac,autofac-configuration,C#,Asp.net Mvc,Dependency Injection,Autofac,Autofac Configuration,我有一个ASP.NET web应用程序,到目前为止,它一直在使用Autofac配置类,该类已为应用程序中的服务指定了一个InstancePerRequest() 从那时起,我在同一个解决方案中创建了一个新的控制台应用程序,它将负责运行自动化作业流程。因为我不能为我的控制台应用程序使用InstancePerRequest配置,所以我需要对配置进行更改。理想情况下,我不想将所有配置复制并粘贴到我的JobRunner应用程序中,并在其中使用“InstancePerLifetimeScope()”配置

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


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


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

虽然
InstancePerLifetimeScope
InstancePerRequest
通常具有相同的权限,但它们的意图肯定不同。我会避免使用
InstancePerLifetimeScope
作为替代品,因为它很容易产生意外的副作用。例如,如果您有一个服务,您原本打算只在web请求期间存在,而它突然在您的应用程序期间存在(因为它无意中从根范围解析)

在作业运行器内部,这种影响会更糟糕,尤其是如果您没有创建自己的生存期范围,那么在这种情况下,所有内容都将存在于根范围中,这意味着一个作业将与依赖于它的所有其他作业共享服务实例

在封面下,
InstancePerRequest()
实际上只是委托给
instancepermatchinglifefetimescope()
一个众所周知的生存期范围标记(可以从
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 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);
    }
}

尽管
InstancePerLifetimeScope
InstancePerRequest
通常具有相同的权限,但它们肯定有不同的意图。我会避免使用
InstancePerLifetimeScope
作为替代品,因为它很容易产生意外的副作用。例如,如果您有一个服务,您原本打算只在web请求期间存在,而它突然在您的应用程序期间存在(因为它无意中从根范围解析)

在作业运行器内部,这种影响会更糟糕,尤其是如果您没有创建自己的生存期范围,那么在这种情况下,所有内容都将存在于根范围中,这意味着一个作业将与依赖于它的所有其他作业共享服务实例

在封面下,
InstancePerRequest()
实际上只是委托给
instancepermatchinglifefetimescope()
一个众所周知的生存期范围标记(可以从
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 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);
    }
}

你的求职者需要一个范围吗?我不确定,是吗?我所要做的就是,每当我在此应用程序中执行作业并在作业完成时终止时,都能够解析我的服务。我的困难只是知道如何设置我的配置,以便它既适合我的web应用程序,也适合作业运行人员。
InstancePerLifetimeScope()
可能就足够了,因为
InstancePerRequest()
只是一个特定的生存期范围,如果没有生存期范围,它应该使用根范围。谢谢John。你能想到任何情况下,这是不够的吗?你需要在你的工作范围运行?我不确定,是吗?我所要做的就是,每当我在此应用程序中执行作业并在作业完成时终止时,都能够解析我的服务。我的困难只是知道如何设置我的配置,以便它既适合我的web应用程序,也适合作业运行人员。
InstancePerLifetimeScope()
可能就足够了,因为
InstancePerRequest()
只是一个特定的生存期范围,如果没有生存期范围,它应该使用根范围。谢谢John。你能想象出哪种情况是不够的吗?谢谢。目前,所有my类型都是使用为每个类型分别指定的作用域注册的,例如“builder.registerType().As().InstancePerLifetimeScope”。如果我调用“builder.RegisterAssemblyTypes().InstancePerMatchingLifetimeScope(lifetimeScope)”,这会消除为每个类型注册指定范围的需要吗?是;但它也将注册所有程序集类型。通常情况下,您会进行筛选,以便只在容器中注册所需的类型;类似于:
builder.RegisterAssemblyTypes().Where(type=>typeof(IJob).IsAssignableFrom(type)).InstancePerMatchingLifetimeScope(lifetimeScope)
谢谢。目前我所有的类型