I have two classes that take a ILastActivityUpdator
as a constructor parameter: UserService
and AnonymousUserService
.
public AnonymousUserService(ILastActivityUpdator lastActivityUpdator)
{
if (lastActivityUpdator == null)
{
throw new ArgumentNullException("lastActivityUpdator");
}
this.lastActivityUpdator = lastActivityUpdator;
}
And similar as above for UserService
:
public UserService(ILastActivityUpdator lastActivityUpdator)
{
if (lastActivityUpdator == null)
{
throw new ArgumentNullException("lastActivityUpdator");
}
this.lastActivityUpdator = lastActivityUpdator;
}
ILastActivityUpdator
interface has one method: UpdateLastActivity(int userId)
. There are two implementations of the interface, a LastActivityUpdator
and a decorator called AnonymousUserLastActivityUpdator
which inherits from LastActivityUpdator
and adds some extra functionality to the method, like so:
public class AnonymousUserLastActivityUpdator
: LastActivityUpdator, IAnonymousUserLastActivityUpdator
{
public AnonymousUserLastActivityUpdator()
{ }
public override void UpdateLastActivity(int userId)
{
base.UpdateLastActivity(userId);
// Extra functionality
}
}
I now want use Autofac to wire up the AnonymousUserService
with the AnonymousUserLastActivityUpdator
and the UserService
with the LastActivityUpdator
.
What I tried is to add an interface for the decorator that derives from the base interface like so:
public interface IAnonymousUserLastActivityUpdator : ILastActivityUpdator
{ }
Then I thought I could use the IAnonymousUserLastActivityUpdator
in the AnonymousUserService
constructor and everything would be autowired properly.
Unfortunately it just always uses the first implementation, being IAnonymousUserLastActivityUpdator
since it is registered earlier (alphabetical order).
How can I accomplish that the AnonymousUserService
gets the AnonymousUserLastActivityUpdator
injected and the UserService
the LastActivityUpdator
?
Constructor Injection Dependency Injection is done by supplying the DEPENDENCY through the class's constructor when creating the instance of that class. The injected component can be used anywhere within the class. Recommended to use when the injected dependency, you are using across the class methods.
Autofac is an open-source dependency injection (DI) or inversion of control (IoC) container developed on Google Code. Autofac differs from many related technologies in that it sticks as close to bare-metal C# programming as possible.
Autofac is nicely documented and it looks like you can find what you are after here. From what I can tell, if you have registered your updators with
builder.RegisterType<LastActivityUpdator>();
builder.RegisterType<AnonymousUserLastActivityUpdator>();
then you should be able to register your services with
builder.Register(c => new UserService(c.Resolve<LastActivityUpdator>()));
builder.Register(c => new AnonymousUserService(c.Resolve<AnonymousUserLastActivityUpdator>()));
or
builder.RegisterType<UserService>().WithParameter(
(p, c) => p.ParameterType == typeof(ILastActivityUpdator),
(p, c) => c.Resolve<LastActivityUpdator>());
builder.RegisterType<AnonymousUserService>().WithParameter(
(p, c) => p.ParameterType == typeof(ILastActivityUpdator),
(p, c) => c.Resolve<AnonymousUserLastActivityUpdator>());
Then when you resolve UserService
or AnonymousUserService
from the container, they will get the correct dependencies.
As an aside, if an interface is injected into a class, then that class should function correctly with all implementations of that interface (LSP). From the class names, it looks like AnonymousUserService
only works with AnonymousUserLastActivityUpdator
and not any implementation of ILastActivityUpdator
. If that is the case, then it might be appropriate to introduce a different abstraction (like IAnonymousUserLastActivityUpdator
) as you suggested.
As stated in the previous response, in this case you're breaking the Liskov principle. In fact, your consumer classes depend on diferent interfaces implementations. Even if the interface are excatly the same one, the functionality it's not. And you need to reflect that:
That you can derive one implementation from the other is completely irrelevant from the DI point of view: it doesn't matter if the implementations are the same class, or are completely independent, or one derives from the other, as in this case.
For more details, check Autofac's Services vs Components docs. You'll see that all the above options are possible.
Taking this into account:
public AnonymousUserService(IAnonymousUserLastActivityUpdator lastActivityUpdator)
public UserService(ILastActivityUpdator lastActivityUpdator)
builder.RegisterType<LastActivityUpdator>()
.As<ILastActivityUpdator>();
builder.RegisterType<AnonymousUserLastActivityUpdator>()
.As<IAnonymousUserLastActivityUpdator>;
In this way, each consumer class will automatically get injected the right implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With