Using Autofac to inject services defined in Web API HttpConfiguration

懵懂的女人 提交于 2019-12-13 02:26:23

问题


When using Autofac with ASP.NET Web API, is there any way to resolve dependencies using the services registered in HttpConfiguration or even the HttpConfiguration itself. For instance, I would like to have a controller with a constructor that receives the config's registered ITraceWriter or the HttpConfiguration itself. I know that the configuration is available in the action methods, but I would like to use it in the constructor.

Thanks.

edit 1

I've found a way to make the current configuration resolvable through the dependency scope, inspired on the Autofac RegisterHttpRequestMessage extension method: register a controller activator that adds the current configuration to the current request scope.

class CurrentConfigurationActivator : IHttpControllerActivator
{
    private readonly IHttpControllerActivator _innerActivator;

    public CurrentConfigurationActivator(IHttpControllerActivator innerActivator)
    {
        _innerActivator = innerActivator;
    }

    public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
    {
        var scope = request.GetDependencyScope();
        var requestScope = scope.GetRequestLifetimeScope();
        if (requestScope != null)
        {
            var registry = requestScope.ComponentRegistry;
            var builder = new ContainerBuilder();
            builder.Register(c => controllerDescriptor.Configuration).InstancePerRequest();
            builder.Update(registry);
        }
        return _innerActivator.Create(request, controllerDescriptor, controllerType);
    }
}

It does work, but is there a better way? Having to decorate the existing activator seems a little bit fragile. Regarding the services registered in the configuration (e.g. ITraceWriter), a way is to manually register each one on the dependency scope using the same technique.


回答1:


The easiest way to do this would be to create a simple Autofac module that does the resolution for you. A snippet might look like this:

public class ServiceModule : Module
{
  protected override void Load(ContainerBuilder builder)
  {
    builder.Register(c =>
                       c.Resolve<HttpRequestMessage>()
                        .GetConfiguration())
           .As<HttpConfiguration>();
    builder.Register(c =>
                       c.Resolve<HttpConfiguration>()
                        .Services
                        .GetService(IApiExplorer) as IApiExplorer)
           .As<IApiExplorer>();

    // Rinse and repeat for every service you want to resolve.
  }
}

Doing it that way would mean you don't need to use any fancy controller activator or whatever - the whole thing would hinge off of the already-working integration that Autofac has for resolving the current request message.

builder.RegisterHttpRequestMessage(config);
builder.RegisterModule<ServiceModule>();

Note that since it all hinges off of the current request message, these won't be resolvable outside a request. If you need them resolvable outside a request, then you can attach the module/resolutions directly to a specific configuration object:

public class ServiceModule : Module
{
  private HttpConfiguration _config;

  public ServiceModule(HttpConfiguration config)
  {
    this._config = config;
  }

  protected override void Load(ContainerBuilder builder)
  {
    builder.RegisterInstance(this._config)
           .As<HttpConfiguration>();
    builder.Register(c =>
                       c.Resolve<HttpConfiguration>()
                        .Services
                        .GetService(IApiExplorer) as IApiExplorer)
           .As<IApiExplorer>();

    // Rinse and repeat for every service you want to resolve.
  }
}

And pass the config in during module construction.

builder.RegisterHttpRequestMessage(config);
builder.RegisterModule(new ServiceModule(config));

The second way will let you resolve things outside a request. Either way will work, it just depends on what you want to do.

If you have something in the pipeline that may somehow change up the config on a per request basis and it's important to get that request's configuration/services, the first way is better. If you don't have that complex of a case, then the second way may be better.

The key is that you want to resolve dependencies using the services registered in HttpConfiguration, not that you want the services in HttpConfiguration to be resolved by Autofac. There's an important difference - the services in HttpConfiguration are largely singletons and are sometimes cached because they're assumed to be singletons. If you try to change that, like trying to register some service as InstancePerRequest or some such, you may run into unexpected problems.



来源:https://stackoverflow.com/questions/23714781/using-autofac-to-inject-services-defined-in-web-api-httpconfiguration

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!