I have an IoCConfig where in the RegisterDependencies method first all Services (same assembly as ServiceBase) are registered, except for one service and one class called LastActivityUpdator and a decorator of this class called AnonymousUserLastActivityUpdator which both implement ILastActivityUpdator.
The goals I want to accomplish is to have the decorator registered properly, which already works following this answer. And I also asked for a way to for one class (UserService) use the LastActivityUpdator and for another (AnonymousUserService) use the AnonymousUserLastActivityUpdator, which was answered here. To be complete (I don't think it is relevant to this problem), I am using a keyed service following this answer to decide which class is injected in other times.
Unfortunately, when I combine the ideas I always see an AnonymousUserLastActivityUpdator injected, also in the case of UserService where I want a LastActivityUpdator to be provided.
Below you'' find the IocConfig which uses both the idea to register the decorator and to provide specific classes with one type:
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();
Unfortunately this does not work. Both the AnonymousUserService and the UserService get an instance of the LastActivityUpdator, while I want AnonymousUserService to get an instance of the AnonymousUserService.
Does anyone know why my RegisterDependencies method does not provide the LastActivityUpdator to UserService and how I can accomplish this?
/edit
Using the answer of Cyril and some adjustments the registering works for the UserService, but once the user logs out and a AnonymousUserService is used I get the error:
Circular component dependency detected:
Services.AnonymousUserService ->
Services.AnonymousUserService ->
Services.AnonymousUserLastActivityUpdator ->
Services.AnonymousUserLastActivityUpdator -> System.Object ->
Services.AnonymousUserLastActivityUpdator
I adjusted the code somewhat of Cyril's answer (fixed some typos and switched the anonymous- and normal UserService) and I might have made a mistake, here it is:
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));
You have 2 kind of registrations for
UserServiceandAnonymousUserService.In the first solution you register
AnonymousUserServiceby explicitly calling the constructor and by asking Autofac to resolve aAnonymousUserLastActivityUpdatorbut there is no registration for this service. Instead of resolving this type, you can resolve a namedILastActivityUpdatorThe second registration is a
Keyedbut you don't specify that theAnonymousUserServiceshould use aanonymousUserLastActivityUpdateryou could do it by using theWithParametermethodYou don't have to have both registration, the last one should be enough for your scenario.