Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Named Services in IoC Containers - A Bad Idea?

It seems like a bad idea to use service keys (or 'named services') when composing a container.

Using named services requires us to either annotate our constructor parameters with matching keys (thus coupling with a container), or to perform additional wiring for each of our services (thus loosing a lot of automation from the container).

For example, I currently have the following interface which is implemented by the following classes:

  • IListSerializer
    • CheckboxListSerializer
    • TreeViewListSerializer

I also have countless classes which depend on either one or both of these classes. However, AFAIK I should be referencing the IListSerializer as my dependency rather than the implementations. This means I have to use keys/names to differentiate between them, which is where it starts to get ugly.

I can see my options as being one of the following:

  • Annotate the constructor parameters (dependencies) with keys. Couples with IoC Container.
  • Perform manual wiring in composition root. Adds repetitive bloat.
  • Reference the classes instead of the interface. Seems like a hack just to satisfy the IoC container.

Any suggestions?

like image 972
Lawrence Wagerfield Avatar asked Jul 12 '11 16:07

Lawrence Wagerfield


People also ask

Why do I need an IoC container as opposed to straightforward DI code?

Whether you will have the need to use some other component in place of the current one, is need based. Use of IOC is to prepare the code for such a change, if it arises IMO.

Which IoC container is best?

You can waste days evaluating IOC containers. The top ones are quite similar. There is not much in this, but the best ones are StructureMap and AutoFac. At SSW we use Autofac on most projects.

What is the important jobs performed by IoC container in Spring?

Spring IoC Container is the core of Spring Framework. It creates the objects, configures and assembles their dependencies, manages their entire life cycle. The Container uses Dependency Injection(DI) to manage the components that make up the application.


1 Answers

In general, the Liskov Substitution Principle is a very useful guide when designing components and services for IoC. If two implementations of a service can't be used interchangeably at runtime, then the service is too general to be meaningful. In this scenario I'd look at using something along the lines of IListSerializer<T> if that is an option for you.

However, if you want to use named services, this is easy and unintrusive to set up with Autofac.

First, register each serializer with its name:

builder.RegisterType<CheckBoxListSerializer>()
    .Named<IListSerializer>("checkBoxSerializer");
builder.RegisterType<TreeViewListSerializer>()
    .Named<IListSerializer>("treeViewSerializer");

Then, add a globally-available parameter that uses the constructor parameter name to choose the right implementation. We can do this with a module:

class NamedParameterResolutionModule<TService> : Module
{
    Parameter _attachedParameter = new ResolvedParameter(
        (pi, c) => pi.ParameterType == typeof(TService),
        (pi, c) => c.ResolveNamed<TService>(pi.Name));

    protected override void AttachToComponentRegistration(
        IComponentRegistry registry,
        IComponentRegistration registration)
    {
        registration.Preparing += (s, e) => {
            e.Parameters = new[] { _attachedParameter }.Contact(e.Parameters);
        };
    }
}

Register the module like so:

builder.RegisterModule<NamedParameterResolutionModule<IListSerializer>>();

Components will then get a serializer depending on the constructor parameter name:

class SomeComponent : ...
{
    public SomeComponent(IListSerializer checkBoxSerializer) { ...
}
like image 183
Nicholas Blumhardt Avatar answered Oct 09 '22 12:10

Nicholas Blumhardt