Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support decorating services without giving a key #874

Closed
fschmied opened this issue Oct 8, 2017 · 3 comments
Closed

Support decorating services without giving a key #874

fschmied opened this issue Oct 8, 2017 · 3 comments

Comments

@fschmied
Copy link

fschmied commented Oct 8, 2017

Currently, Autofac's decorator feature requires either a fromKey or a toKey to be given. I'd like to suggest changing this so that neither key needs to be specified. In such a case, Autofac should just decorate all the registrations for the given service type.

If multiple decorators are registered, they should probably be chained in the order of registration to be consistent with how multiple registrations behave with Resolve<IEnumerable<...>>(). (More elaborate configuration of decorator dependencies might be desirable but is probably out of scope for this feature request.)

Motivation

In our projects, we often have the requirement of decorating instances registered by other modules in library assemblies. For example, module A in a library component would register an IService, module B would like to decorate that IService. These services are not registered with keys because they should be resolvable without giving a key.

public class ModuleA : Module
{
  public override void Load(ContainerBuilder builder)
  {
    builder.Register(c => new DefaultService(c.Resolve<SomeParameterService>(), "some parameter", 42))
      .As<IService>();
  }
}

public class ModuleB : Module
{
  public override void Load(ContainerBuilder builder)
  {
    builder.RegisterDecorator<IService>((ctx, decorated) => new ServiceDecorator(decorated), fromKey: null);
  }
}

At the moment, this does not work, it gives an ArgumentException:

The service IService cannot be both the adapter's from and to parameters - these must differ.

This means that we cannot use the RegisterDecorator feature in our scenario. Instead, we need to copy the registration from ModuleA to ModuleB. (Since ModuleA is in a library, we can't just refactor the registration code into a common abstraction.)

public class ModuleB : Module
{
  public override void Load(ContainerBuilder builder)
  {
    builder.Register((ctx, decorated) => new ServiceDecorator(new DefaultService(c.Resolve<SomeParameterService>(), "some parameter", 42)))
      .As<IService>();
  }
}

This is cumbersome and reduces maintainability, and it doesn't work for collections (IService will now have two registrations rather than just the decorated one).

@ShadowDancer
Copy link

ShadowDancer commented Oct 19, 2017

+1, I am really surprised that Autofac supports some weird case of keyed decorators, but doesn't support this straightforward way.

Example use case:

    if(debug){
        builder.RegisterGenericDecorator<QueryPerformanceCounter<>, IDbQuery<>>, 
    }

@tillig
Copy link
Member

tillig commented Oct 27, 2017

We're pushing to enhance decorator syntax and features, which will hopefully resolve this issue. I've created a larger meta-issue for tracking that at #880. In the meantime, I'll close this specific issue and hopefully we can handle everything at once.

@tillig tillig closed this as completed Oct 27, 2017
@drauch
Copy link

drauch commented Dec 21, 2017

In our team we introduced an extension method RegisterDecorator() which uses the .Activating handler to decorate the instance. Maybe that's a solution for you @fschmied ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants