Raffaeu
Raffaeu

Reputation: 6973

Specify to Autofac which Named service to resolve

I have two different services (Entity Framework contexts) that I inject all over my application and registered as following:

builder.Register<WriteContext>().Named("Write");
builder.Register<ReadContext>().Named("Read");

Now, I have two different command handlers (I have more than two) and each one gets injected a DbContext as following:

public class CommandAHandler : ICommandHandler {

    private readonly DbContext context;
    // this handler should get "Write" context
    public CommandAHandler(DbContext context) {
       this.context = context;
    }

}

public class CommandBHandler : ICommandHandler {

    private readonly DbContext context;
    // this handler should get "Read" context
    public CommandBHandler(DbContext context) {
       this.context = context;
    }

}

How can I specify to CommandAHandler to get an instance of type "Write" and to CommandBHandler to get an instance of type "Read"? Using, of course, Autofac registration

Upvotes: 2

Views: 529

Answers (3)

Steven
Steven

Reputation: 172646

You are violating the Liskov Substitution Principle here (and therefore the SOLID principles). You have one 'abstraction' (i.e. DbContext) but if you inject the readonly version into a consumer that expects the writable, the application will break. This is a strong indication that you are violating LSP.

The LSP dictates that you have different abstractions for each case. This basically means you should inject ReadContext and WriteContext directly. This will immediately solve your registration problem, because you can define your handlers as:

public CommandAHandler(WriteContext context)
public CommandBHandler(ReadContext context)

This allows you to simplify your registration to the following:

builder.Register<WriteContext>();
builder.Register<ReadContext>();

Upvotes: 2

Darxis
Darxis

Reputation: 1570

Assuming WriteContext and ReadContext are registered as DbContext:

builder
    .RegisterType<CommandAHandler>()
    .WithParameters(
        new[] {
            new ResolvedParameter(
                (pi, ctx) => pi.ParameterType == typeof(DbContext),
                (pi, ctx) => ctx.ResolveNamed<DbContext>("Write")
            )
        });
builder
    .RegisterType<CommandBHandler>()
    .WithParameters(
        new[] {
            new ResolvedParameter(
                (pi, ctx) => pi.ParameterType == typeof(DbContext),
                (pi, ctx) => ctx.ResolveNamed<DbContext>("Read")
            )
        });

Upvotes: 0

Johnny
Johnny

Reputation: 9519

You can use lambda expression to register handlers into Ioc. For example:

builder.Register(c => new CommandAHandler(c.Resolve<WriteContext>()));
builder.Register(c => new CommandBHandler(c.Resolve<ReadContext>()));

Upvotes: 1

Related Questions