Autofac.WebApi2 全局操作过滤器注入失败
Autofac.WebApi2 Global Action FIlters injection failed
我面临的问题是 AutoFac 没有将预期的参数注入相应的过滤器。
我有一个过滤器,用于记录我所有控制器中所有方法的执行持续时间。为了完成这个任务,我创建了一个像这样的 ActionFilter:
//... other usings here...
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace MyNamespace
{
internal class ExecutionTimeFilter : ActionFilterAttribute
{
public Logger _logger { get; set; }
public ExecutionTimeFilter(Logger logger)
{
_logger = logger;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
_logger.Log("Log the starting time + controller + action + etc");
actionContext.Request.Properties["Stopwatch"] = Stopwatch.StartNew();
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var stopwatch = (Stopwatch)actionExecutedContext.Request.Properties["Stopwatch"];
_logger.Log("Log the stopwatch.ElapsedMilliseconds + controller + action + etc");
}
}
}
我正在注册我的依赖项如下:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
var container = new IocConfiguration().Configure(GlobalConfiguration.Configuration);
var resolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
//This is the only way I can get the logger injected
//This is what ideally I want to avoid
GlobalConfiguration.Configuration.Filters.Add(new ExecutionTimeFilter(_logger));
}
//IocConfiguration
using Autofac;
using Autofac.Integration.WebApi;
using System.Reflection;
using System.Web.Http;
using System.Web.Mvc;
namespace MyNamespace
{
internal class IocConfiguration
{
public IContainer Configure(HttpConfiguration httpConfiguration)
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterInstance(LogManager.GetLogger("LoggerName")).As<Logger>().SingleInstance();
builder.RegisterWebApiFilterProvider(httpConfiguration);
return builder.Build();
}
}
}
如果我按照 official site 中描述的步骤进行操作,我会收到代码片段后描述的错误:
var builder = new ContainerBuilder();
builder.Register(c => new ExecutionTimeFilter(c.Resolve<Logger>()))
.AsWebApiActionFilterFor<MyController>()
.InstancePerRequest();
The type 'MyController' must be assignable to
'Autofac.Integration.WebApi.IAutofacActionFilter'. Parameter name:
registration
这里是控制器的摘录:
//...Other usings...
using System.Threading.Tasks;
using System.Web.Http;
using System;
namespace MyNamespace.Controllers
{
public class MyController : ApiController
{
private readonly Logger _logger;
public MarketoController(Logger logger)
{
_logger = logger;
}
}
[HttpGet]
[Route("path/{entityId}")]
[ValidateEntityId]
public async Task<IHttpActionResult> Get(int? entityId = null)
{
return Ok();
}
}
我错过了什么?
我看到您的过滤器 ExecutionTimeFilter
继承自 ActionFilterAttribute
。 If you notice in the docs Autofac 过滤器机制不使用 Web API 动作过滤器接口。
异常消息有点令人困惑,但我猜问题是您正尝试在注册中使用 Web API 属性过滤器,而该注册期望您使用 Autofac 过滤器接口。
您可能在文档中错过的关键步骤是第二步,它说:
Instead of deriving from one of the existing Web API filter attributes your class implements the appropriate filter interface defined in the integration. The filter below is an action filter and implements IAutofacActionFilter
instead of System.Web.Http.Filters.IActionFilter
.
我在最重要的地方加了粗体。
文档归结为:
- 如果你想使用
Register(...).AsWebApiActionFilterFor<T>()
东西,你需要使用 Autofac 过滤器接口。
- 如果您想使用标准 Web API 过滤器,您需要进行服务定位,因为标准 Web API 过滤器不会 运行 通过依赖注入。
文档中有关于 Autofac 使用自定义接口的确切原因以及 DI 不能与标准过滤器一起工作的原因的详细解释。
我面临的问题是 AutoFac 没有将预期的参数注入相应的过滤器。
我有一个过滤器,用于记录我所有控制器中所有方法的执行持续时间。为了完成这个任务,我创建了一个像这样的 ActionFilter:
//... other usings here...
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
namespace MyNamespace
{
internal class ExecutionTimeFilter : ActionFilterAttribute
{
public Logger _logger { get; set; }
public ExecutionTimeFilter(Logger logger)
{
_logger = logger;
}
public override void OnActionExecuting(HttpActionContext actionContext)
{
_logger.Log("Log the starting time + controller + action + etc");
actionContext.Request.Properties["Stopwatch"] = Stopwatch.StartNew();
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var stopwatch = (Stopwatch)actionExecutedContext.Request.Properties["Stopwatch"];
_logger.Log("Log the stopwatch.ElapsedMilliseconds + controller + action + etc");
}
}
}
我正在注册我的依赖项如下:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
var container = new IocConfiguration().Configure(GlobalConfiguration.Configuration);
var resolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
//This is the only way I can get the logger injected
//This is what ideally I want to avoid
GlobalConfiguration.Configuration.Filters.Add(new ExecutionTimeFilter(_logger));
}
//IocConfiguration
using Autofac;
using Autofac.Integration.WebApi;
using System.Reflection;
using System.Web.Http;
using System.Web.Mvc;
namespace MyNamespace
{
internal class IocConfiguration
{
public IContainer Configure(HttpConfiguration httpConfiguration)
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterInstance(LogManager.GetLogger("LoggerName")).As<Logger>().SingleInstance();
builder.RegisterWebApiFilterProvider(httpConfiguration);
return builder.Build();
}
}
}
如果我按照 official site 中描述的步骤进行操作,我会收到代码片段后描述的错误:
var builder = new ContainerBuilder();
builder.Register(c => new ExecutionTimeFilter(c.Resolve<Logger>()))
.AsWebApiActionFilterFor<MyController>()
.InstancePerRequest();
The type 'MyController' must be assignable to 'Autofac.Integration.WebApi.IAutofacActionFilter'. Parameter name: registration
这里是控制器的摘录:
//...Other usings...
using System.Threading.Tasks;
using System.Web.Http;
using System;
namespace MyNamespace.Controllers
{
public class MyController : ApiController
{
private readonly Logger _logger;
public MarketoController(Logger logger)
{
_logger = logger;
}
}
[HttpGet]
[Route("path/{entityId}")]
[ValidateEntityId]
public async Task<IHttpActionResult> Get(int? entityId = null)
{
return Ok();
}
}
我错过了什么?
我看到您的过滤器 ExecutionTimeFilter
继承自 ActionFilterAttribute
。 If you notice in the docs Autofac 过滤器机制不使用 Web API 动作过滤器接口。
异常消息有点令人困惑,但我猜问题是您正尝试在注册中使用 Web API 属性过滤器,而该注册期望您使用 Autofac 过滤器接口。
您可能在文档中错过的关键步骤是第二步,它说:
Instead of deriving from one of the existing Web API filter attributes your class implements the appropriate filter interface defined in the integration. The filter below is an action filter and implements
IAutofacActionFilter
instead ofSystem.Web.Http.Filters.IActionFilter
.
我在最重要的地方加了粗体。
文档归结为:
- 如果你想使用
Register(...).AsWebApiActionFilterFor<T>()
东西,你需要使用 Autofac 过滤器接口。 - 如果您想使用标准 Web API 过滤器,您需要进行服务定位,因为标准 Web API 过滤器不会 运行 通过依赖注入。
文档中有关于 Autofac 使用自定义接口的确切原因以及 DI 不能与标准过滤器一起工作的原因的详细解释。