如何使用 Autofac 在一个构造函数中注入类的装饰器,在另一个构造函数中注入类本身

本文关键字:注入 构造函数 另一个 何使用 一个 Autofac | 更新日期: 2023-09-27 17:57:06

我有一个IoCConfig,在 RegisterDependencies 方法中,首先注册所有Services(与ServiceBase相同的程序集),除了一个名为 LastActivityUpdator 的服务和一个类以及一个名为 AnonymousUserLastActivityUpdator 的此类装饰器,它们都实现了 ILastActivityUpdator

我想要实现的目标是正确注册装饰器,它已经在这个答案之后工作了。我还要求一种方法,让一个类(UserService)使用LastActivityUpdator,而另一个类(AnonymousUserService)使用AnonymousUserLastActivityUpdator,这在这里得到了回答。为了完整(我认为这与这个问题无关),我正在使用此答案的键控服务来决定在其他时间注入哪个类。

不幸的是,当我结合这些想法时,我总是看到注入AnonymousUserLastActivityUpdator,在我希望提供LastActivityUpdatorUserService的情况下也是如此。

在下面找到IocConfig,它既使用想法来注册装饰器,又使用一种类型提供特定类:

builder.RegisterAssemblyTypes(typeof(ServiceBase).Assembly)
    .Except<AnonymousUserService>()
    .Except<LastActivityUpdator>()
    .Except<AnonymousUserLastActivityUpdator>()
    .AsImplementedInterfaces()
    .InstancePerRequest();
builder.RegisterType<LastActivityUpdator>()
    .Named<ILastActivityUpdator>("lastActivityUpdator");
builder.RegisterType<AnonymousUserLastActivityUpdator>()
    .Named<ILastActivityUpdator>("anonymousUserLastActivityUpdator");
builder.RegisterDecorator<ILastActivityUpdator>(
    (c, inner) => c.ResolveNamed<ILastActivityUpdator>("anonymousUserLastActivityUpdator", 
        TypedParameter.From(inner)),
    fromKey: "lastActivityUpdator")
    .As<ILastActivityUpdator>();
builder.Register(c => new UserService(
    c.Resolve<OogstplannerUnitOfWork>(),
    c.Resolve<CookieProvider>(),
    c.Resolve<ILastActivityUpdator>()));
builder.Register(c => new AnonymousUserService(
    c.Resolve<OogstplannerUnitOfWork>(),
    c.Resolve<CookieProvider>(),
    c.Resolve<AnonymousUserLastActivityUpdator>()));
builder.RegisterType<AnonymousUserService>()
    .Keyed<IUserService>(AuthenticatedStatus.Anonymous)
    .InstancePerRequest();
builder.RegisterType<UserService>()
    .Keyed<IUserService>(AuthenticatedStatus.Authenticated)
    .InstancePerRequest();

不幸的是,这不起作用。AnonymousUserServiceUserService都得到LastActivityUpdator的实例,而我希望AnonymousUserService得到AnonymousUserService的实例。

有谁知道为什么我的 RegisterDependencies 方法不提供UserService LastActivityUpdator以及如何完成此操作?

/编辑

使用 Cyril 的答案和一些调整,注册适用于UserService,但是一旦用户注销并使用AnonymousUserService,我就会收到错误:

检测到循环组件依赖关系:
服务.匿名用户服务 -> 服务.匿名用户服务 -> 服务.匿名用户最后活动更新器 -> 服务.匿名用户最后活动更新器 -> 系统.对象 ->



服务.匿名用户最后活动更新器

我稍微调整了 Cyril 答案的代码(修复了一些拼写错误并切换了匿名和普通用户服务),我可能犯了一个错误,这里是:

builder.RegisterAssemblyTypes(typeof(ServiceBase).Assembly)
    .Except<AnonymousUserService>()
    .Except<LastActivityUpdator>()
    .Except<AnonymousUserLastActivityUpdator>()
    .AsImplementedInterfaces()
    .InstancePerRequest();
builder.RegisterType<LastActivityUpdator>()
    .Named<ILastActivityUpdator>("lastActivityUpdator");
builder.RegisterType<AnonymousUserLastActivityUpdator>()
    .Named<ILastActivityUpdator>("anonymousUserLastActivityUpdator");
builder.RegisterDecorator<ILastActivityUpdator>(
    (c, inner) => c.ResolveNamed<ILastActivityUpdator>("anonymousUserLastActivityUpdator", 
        TypedParameter.From(inner)),
    fromKey: "lastActivityUpdator")
    .As<ILastActivityUpdator>();
builder.RegisterType<UserService>()
    .Keyed<IUserService>(AuthenticatedStatus.Authenticated)
    .WithParameter(
        (p, c) => p.Name == "lastActivityUpdator", 
        (p, c) => c.ResolveNamed<ILastActivityUpdator>("lastActivityUpdator"))
    .InstancePerRequest();
builder.RegisterType<AnonymousUserService>()
    .Keyed<IUserService>(AuthenticatedStatus.Anonymous)
    .WithParameter(
        (p, c) => p.Name == "anonymousUserLastActivityUpdator", 
        (p, c) => c.ResolveNamed<ILastActivityUpdator>("anonymousUserLastActivityUpdator"))
    .InstancePerRequest();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

如何使用 Autofac 在一个构造函数中注入类的装饰器,在另一个构造函数中注入类本身

您有 2 种UserServiceAnonymousUserService注册。

在第一个解决方案中,通过显式调用构造函数并要求 Autofac 解析AnonymousUserLastActivityUpdator来注册AnonymousUserService,但没有注册此服务。您可以解析命名ILastActivityUpdator,而不是解析此类型

builder.Register(c => new UserService(
    c.Resolve<OogstplannerUnitOfWork>(),
    c.Resolve<CookieProvider>(),
    c.Resolve<ILastActivityUpdator>()));
builder.Register(c => new AnonymousUserService(
    c.Resolve<OogstplannerUnitOfWork>(),
    c.Resolve<CookieProvider>(),
    c.ResolveNamed<ILastActivityUpdator>("anonymousUserLastActivityUpdator")));

第二个注册是Keyed但你没有指定AnonymousUserService应使用anonymousUserLastActivityUpdater你可以使用 WithParameter 方法执行此操作

builder.RegisterType<AnonymousUserService>()
       .Keyed<IUserService>(AuthenticatedStatus.Authenticated)
       .InstancePerRequest();
builder.RegisterType<UserService>()
       .Keyed<IUserService>(AuthenticatedStatus.Anonymous)
       .WithParameter(
         (pi, c) => pi.Name == "updater", 
         (pi, c) => ResolveNamed<ILastActivityUpdator>("anonymousUserLastActivityUpdator"))
       .InstancePerRequest();

不必同时进行两次注册,最后一个注册应该足以满足你的方案。