首页 > 解决方案 > Autofac 按上下文解析

问题描述

因此,我基本上计划从 RavenDb 切换到 MongoDb,并对我的存储库进行不同的实现。我将 CQRS 与消息调度程序一起使用,我希望使用两组存储库运行我的消费者两次

       builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(Consumers.IMessageConsumer<>))).AsClosedTypesOf(typeof(Consumers.IMessageConsumer<>));


        builder.RegisterType<RavenUserRepository>().As<IUserRepository>().InstancePerLifetimeScope();
        builder.RegisterType<MongoUserRepostiory>().As<IUserRepository>().InstancePerLifetimeScope();


    public Task Dispatch<TMessage>(TMessage message) where TMessage : IMessage
    {

        // Raven

        using (var scope = _lifetimeScope.BeginLifetimeScope())
        {
            var consumer = scope.Resolve<IMessageConsumer<TMessage>>();

            consumer.Handle(message, CancellationToken.None);
        }

        // Mongo

        using (var scope = _lifetimeScope.BeginLifetimeScope())
        {
            var consumer = scope.Resolve<IMessageConsumer<TMessage>>();

            consumer.Handle(message, CancellationToken.None);
        }

        return Task.CompletedTask;
    }

所以我基本上想告诉每个生命周期范围它允许使用哪些存储库。我正在撞砖墙,但似乎无法解决

标签: c#dependency-injectionautofac

解决方案


这种场景在此处被大量记录: https ://autofaccn.readthedocs.io/en/latest/faq/select-by-context.html 。根据您的整体方法,您可以选择很多选项,例如在您过渡时是否支持两个回购只是一个短期解决方案。

使用该方法的解决方案之一的示例如下Keyed。如果我们在 repo 注册中添加一个密钥:

public enum RepoType
{
    Raven,
    Mongo
}

...

builder.RegisterType<RavenUserRepository>().Keyed<IUserRepository>(RepoType.Raven).InstancePerLifetimeScope();
builder.RegisterType<MongoUserRepostiory>().Keyed<IUserRepository>(RepoType.Mongo).InstancePerLifetimeScope();

而不是

builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(Consumers.IMessageConsumer<>))).AsClosedTypesOf(typeof(Consumers.IMessageConsumer<>));

我们有

builder.RegisterGeneric(typeof(MessageConsumer<>))
    .Keyed(RepoType.Mongo, typeof(IMessageConsumer<>)).WithParameter(
        new ResolvedParameter(
            (pi, ctx) => pi.ParameterType == typeof(IUserRepository),
            (pi, ctx) => ctx.ResolveKeyed<IUserRepository>(RepoType.Mongo)));

builder.RegisterGeneric(typeof(MessageConsumer<>))
    .Keyed(RepoType.Raven, typeof(IMessageConsumer<>))
    .WithParameter(
        new ResolvedParameter(
            (pi, ctx) => pi.ParameterType == typeof(IUserRepository),
            (pi, ctx) => ctx.ResolveKeyed<IUserRepository>(RepoType.Raven)));

最后一部分不是最漂亮的,但对于每个 repo,它基本上是在说“IConsumer<>用一个密钥注册一个,它在内部使用IUserRepository相同的密钥解析”。然后,我们可以IConsumer<>根据使用代码的需要解析 s ,或者作为IEnumerable<>(如果您有多个服务注册,这将自动从 Autofac 获得)或单独使用我们的密钥:

var consumers = scope.Resolve<IEnumerable<IMessageConsumer<T>>>();
foreach (var messageConsumer in consumers)
{
    messageConsumer.Handle(message, CancellationToken.None);
}

或者

var mongoConsumer = scope.ResolveKeyed<IMessageConsumer<T>>(RepoType.Mongo);
mongoConsumer.Handle(message, CancellationToken.None);

var ravenConsumer = scope.ResolveKeyed<IMessageConsumer<T>>(RepoType.Raven);
ravenConsumer.Handle(message, CancellationToken.None);

推荐阅读