Search code examples
c#dynamicdependency-injectionautofacconstructor-injection

Is it possible to have some kind of dynamic KeyFilter in autofac?


KeyFilter used in Autofac is helpful but really I think it's not dynamic because the key here is preset/setup/defined and attached to constructor parameters at compile time. No way to have something similar working at runtime.

Here is the scenario, at the time resolving for some instance, the key can be determined (which can change dynamically based on the current context). That key then should be taken into account before resolving for the instance. I think Multitenant feature supported by autofac is something very close to that requirement. However I don't think it can be easily used and supports constructor injection (we may have to always create a scope and resolve for instances explicitly and manually, which looks much like a service locator's way).

So applied that imaginary feature in code version picking example, let's see how helpful it can be. Suppose I have 2 implementations for a same interface, each corresponds to one code version (v1 and v2). Now the constructor consuming that interface does not care about which version, but the context will provide the IoC container which version so that it should resolve for the correct implementation corresponding to the that version.

public interface ISender {
    void Send(string msg);
}
//version v1 
public class SlowSender : ISender {
    //...
}
//version v2
public class FastSender : ISender {
    //...
}

Now's the consumer class:

public class MyConsumer {
    readonly ISender _sender;
    public MyConsumer(ISender sender){
        _sender = sender;
    }
    //do whatever with what ISender provides
}

So here when resolving for MyConsumer, autofac should know about which version it is to pick for me, such as via some context info provider like this:

public class ContextInfoProvider : IContextInfoProvider //just an example
{
    public string GetCurrentVersion(){
        //can return some value picked from HttpContext.Current.Request
        //or any ambient variable that can be injected at some very early time.
    }
}

That's kind of a service (very fast service) to help autofac know of which should be taken into account (as an input, a parameter) for the instance resolving process.

I know this is possible but may have not been implemented yet by autofac. It's really a pity. Do you have any alternative solution with the current features supported by autofac? Please note that I don't want to use service-locator-like code, sometimes we have to use it that way but almost the time we need a constructor-dependency-injection's way, it's just neat and clean.


Solution

  • You could register a lambda. Put the factory logic in that lambda.

    builder.Register(ctx =>
      var version = ctx.Resolve<IContextInfoProvider>().GetVersion();
      if(version == 1)
      {
        return new SlowSender();
      }
      return new FastSender();
    ).As<ISender>();