Search code examples
c#adapterautofac

How do I register an Autofac "Adapter" that has dependencies?


Autofac provides RegisterAdapter, an easy way to wrap (or adapt) an implementation:

builder.RegisterAdapter<Meta<ICommand>, ToolbarButton>(
    cmd => new ToolbarButton(cmd.Value, (string)cmd.Metadata["Name"]));

This is cool, but what if my adapter constructor requires DI support? Suppose my ToolbarButton constructor looks like this:

public ToolbarButton(ICommand cmd, IService1 svc1, IService2 svc2) { ... }

And I just want to inject my ToolbarButton collection as a composite, so I don't need metadata:

public Toolbar(IEnumerable<ToolbarButton> buttons) { ... }

So I'm looking for the best way to register my ICommand adapter. It seems like I should be able to do something like this, letting Autofac resolve dependent services for each adapter it creates:

builder.RegisterAdapter<ICommand, ToolbarButton>();

But there is no such signature for RegisterAdapter(). (Why?)

So instead I'm having to do something like this, which seems kind of anti-patterny and redundant:

builder.RegisterAdapter<ICommand, ToolbarButton>((ctx, from) =>
    new ToolbarButton(from, ctx.Resolve<IService2>(), ctx.Resolve<IService2>()));

Or if I don't want to list out each of my dependencies, I can pass ICommand as a parameter:

builder.RegisterAdapter<ICommand, ToolbarButton>((ctx, from) =>
    ctx.Resolve<ToolbarButton>(new TypedParameter(typeof(ICommand), from)));

This is also ugly and, again, it feels like I'm telling Autofac stuff it should already know. Is there a better way?


Solution

  • It feels ugly but that's pretty much it. If it was a decorator rather than an adapter you'd get more "free magic," but since adapters can require more complex setup (it's not always just constructor parameters) all that's offered right now is what you've found: you have to do the work in the factory function.

    If you have ideas for different behavior, you can always open an issue with your proposal.