首页 > 解决方案 > 每个范围的 Autofac 独特服务

问题描述

我的目标是根据范围提供接口实现。

我想用下面的代码解决这个问题,但这会导致 A 被 B 覆盖

var containerBuilder = new ContainerBuilder();

containerBuilder.RegisterType<ImplA>().As<IMyInterface>().InstancePerMatchingLifetimeScope(MyScope.A);
containerBuilder.RegisterType<ImplB>().As<IMyInterface>().InstancePerMatchingLifetimeScope(MyScope.B);

IContainer container = containerBuilder.Build();
using (ILifetimeScope lifetimeScope = container.BeginLifetimeScope(MyScope.A))
{
    IMyInterface c = lifetimeScope.Resolve<IMyInterface>();
    Console.WriteLine(c.GetType());
}

using (ILifetimeScope lifetimeScope = container.BeginLifetimeScope(MyScope.B))
{
    var c = lifetimeScope.Resolve<IMyInterface>();
    Console.WriteLine(c.GetType());
}

我知道我可以通过以下方式在生命周期内注册类型,但我想从一个Module

using (ILifetimeScope lifetimeScope = container.BeginLifetimeScope(MyScope.A, builder =>
{
    containerBuilder.RegisterType<ImplA>().As<IMyInterface>();
}))

有没有办法在模块级别解决这个问题?

标签: c#dependency-injectionautofac

解决方案


我目前的解决方案如下

public static class AutofacExtension
{
    private class ScopeModule
    {
        private readonly Action<ContainerBuilder> _action;

        public ScopeModule(object lifetimeScopeTag, Action<ContainerBuilder> action)
        {
            _action = action;
        }

        public void ConfigurationAction(ContainerBuilder lifetimeScope)
        {
            _action(lifetimeScope);
        }
    }

    public static void ForScope(this ContainerBuilder containerBuilder, object scope, Action<ContainerBuilder> action)
    {
        containerBuilder
            .RegisterInstance(new ScopeModule(scope, action))
            .Keyed<ScopeModule>(scope)
            .SingleInstance();
    }

    public static ILifetimeScope BeginModuleLifetimeScope(this IContainer container, object scope, Action<ContainerBuilder> configurationAction = null)
    {
        return container.BeginLifetimeScope(scope, lifeTimeScopeContainerBuilder =>
        {
            var scopeModules = container.ResolveKeyed<IEnumerable<ScopeModule>>(scope);
            foreach (ScopeModule scopeModule in scopeModules)
            {
                scopeModule.ConfigurationAction(lifeTimeScopeContainerBuilder);
            }
            configurationAction?.Invoke(lifeTimeScopeContainerBuilder);
        });
    }
}

用法

var containerBuilder = new ContainerBuilder();

containerBuilder.ForScope(MyScope.A, scope => scope.RegisterType<ImplA>().As<IMyInterface>());
containerBuilder.ForScope(MyScope.B, scope => scope.RegisterType<ImplB>().As<IMyInterface>());

IContainer container = containerBuilder.Build();
using (ILifetimeScope lifetimeScope = container.BeginModuleLifetimeScope(MyScope.A))
{
    IMyInterface c = lifetimeScope.Resolve<IMyInterface>();
    Console.WriteLine(c.GetType());
}

using (ILifetimeScope lifetimeScope = container.BeginModuleLifetimeScope(MyScope.B))
{
    var c = lifetimeScope.Resolve<IMyInterface>();
    Console.WriteLine(c.GetType());
}

推荐阅读