在Web API 2中,如何在Application_PostResolveRequestCache中确定要调用的Action?
解决在控制器创建前确定Web API调用Action的问题
核心问题分析
你需要在Application_PostResolveRequestCache阶段提前确定要调用的Action,以此选择对应的依赖注入实现,但当前创建的HttpControllerContext中RouteData为null——这是导致ApiControllerActionSelector.SelectAction无法正常工作的关键,因为Action选择逻辑严重依赖路由数据匹配控制器和Action的路由模板。
获取正确RouteData的方法
在Application_PostResolveRequestCache阶段,请求的路由已完成解析,可直接从HttpRequestMessage中获取路由数据,再手动赋值给HttpControllerContext:
修改CreateControllerContext方法
调整现有方法,添加RouteData赋值逻辑:
private static HttpControllerContext CreateControllerContext( HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor ) { HttpConfiguration configuration1 = controllerDescriptor.Configuration; HttpConfiguration configuration2 = request.GetConfiguration(); if (configuration2 == null) { request.SetConfiguration(configuration1); } else if (configuration2 != configuration1) { request.SetConfiguration(configuration1); } HttpRequestContext httpRequestContext1 = request.GetRequestContext(); // 从请求中获取已解析的RouteData var routeData = request.GetRouteData(); var controller = (IHttpController)FormatterServices.GetUninitializedObject(controllerDescriptor.ControllerType); var controllerContext = new HttpControllerContext(httpRequestContext1, request, controllerDescriptor, controller); // 为ControllerContext赋值RouteData controllerContext.RouteData = routeData; return controllerContext; }
完整的Action选择流程
- 获取控制器描述符:通过
IHttpControllerSelector从请求中解析对应的HttpControllerDescriptor - 创建带RouteData的ControllerContext:使用修改后的方法创建上下文
- 调用Action选择器:获取配置中的
ApiControllerActionSelector实例,调用SelectAction得到目标Action
示例代码片段:
protected void Application_PostResolveRequestCache() { var request = HttpContext.Current.Items["MS_HttpRequestMessage"] as HttpRequestMessage; if (request == null) return; var config = request.GetConfiguration(); // 获取控制器选择器 var controllerSelector = config.Services.GetHttpControllerSelector(); var controllerDescriptor = controllerSelector.SelectController(request); // 创建带RouteData的ControllerContext var controllerContext = CreateControllerContext(request, controllerDescriptor); // 获取Action选择器并选择目标Action var actionSelector = config.Services.GetActionSelector(); var actionDescriptor = actionSelector.SelectAction(controllerContext); // 根据actionDescriptor的信息(如ActionName、ControllerName等)选择对应的依赖注入实现 // 此处添加你的依赖注入逻辑 }
注意事项
Application_PostResolveRequestCache阶段刚好是路由匹配完成、控制器创建之前的节点,完全符合你的需求场景- 若使用自定义路由或Action选择逻辑,需确保
config.Services中注册的选择器是实际使用的实现,避免匹配不一致 - 使用
FormatterServices.GetUninitializedObject创建控制器实例时不会调用构造函数,不会触发依赖注入,契合你在注入前判断Action的需求
内容的提问来源于stack exchange,提问作者Matt Mills
相关产品推荐
相关产品推荐

