使用Autofac注入Web API HttpConfiguration中定义的服务

时间:2014-05-17 18:33:13

标签: asp.net autofac asp.net-web-api

将Autofac与ASP.NET Web API一起使用时,有没有办法使用HttpConfiguration中注册的服务甚至HttpConfiguration本身来解析依赖关系。 例如,我想有一个带有构造函数的控制器,它接收配置的注册ITraceWriterHttpConfiguration本身。 我知道配置在action方法中可用,但我想在构造函数中使用它。

感谢。

编辑1

我已经找到了一种方法,可以通过依赖范围使当前配置可以解析,这可以通过Autofac RegisterHttpRequestMessage扩展方法获得:注册一个控制器激活器,将当前配置添加到当前请求范围。 / p>

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);
    }
}

它确实有效,但有更好的方法吗?必须装饰现有的激活器似乎有点脆弱。 关于在配置中注册的服务(例如ITraceWriter),一种方法是使用相同的技术在依赖范围上手动注册每个服务。

1 个答案:

答案 0 :(得分:1)

最简单的方法是创建一个简单的Autofac模块,为您解决问题。一个片段可能如下所示:

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.
  }
}

这样做意味着您不需要使用任何花哨的控制器激活器或其他任何东西 - 整个事情将取决于Autofac用于解析当前请求消息的已经工作的集成。

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

请注意,由于它全部取决于当前请求消息,这些不会在请求之外解析。如果您需要在请求之外解析它们,那么您可以将模块/解决方案直接附加到特定配置对象:

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.
  }
}

在模块构建期间传递配置。

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

第二种方式可让您解决请求之外的事情。无论哪种方式都可行,只取决于您的目标。

如果您在管道中有某些内容可能以某种方式在每个请求的基础上更改配置,并且获得该请求的配置/服务很重要,第一种方式更好。如果你没有案件的复杂性,那么第二种方式可能会更好。

关键是您希望使用在HttpConfiguration中注册的服务解决依赖关系,而不是您希望Autofac解析HttpConfiguration中的服务。有一个重要的区别 - HttpConfiguration中的服务主要是单身,有时会被缓存,因为它们被认为是单身。如果您尝试更改它,例如尝试将某些服务注册为InstancePerRequest或某些服务,则可能会遇到意外问题。