我正在尝试为我的 Web API 2.2 项目使用自定义控制器选择器,该项目使用命名空间选择进行版本控制。该项目是自托管的。
网上有很多关于这方面的文章,但大多数都只涉及一个用例(即仅常规路由,或仅属性路由但没有路由前缀等)。
就我而言,我想使用所有的 cookie。换句话说,我的选择器必须支持这些:
namespace WebProject.Controllers.v1
{
[RoutePrefix("accounts")]
public class AccountsController : ApiController
{
[Route("")]
public IHttpActionResult Get()
{
var accounts = accountList.ConvertAll(LogicMgr.ConvertModelToView);
return Ok(accounts);
}
}
}
namespace WebProject.Controllers.v2
{
[RoutePrefix("accounts")]
public class AccountsController : ApiController
{
[Route("")]
public IHttpActionResult Get()
{
var accounts = accountList.ConvertAll(LogicMgr.ConvertModelToView);
return Ok(accounts);
}
}
}
任何选择器的主要部分是从请求中提取控制器名称。在大多数文章中,这是通过具有特定键(“控制器”)的字典来完成的。但这仅适用于传统的模板路由。
在处理属性路由时,建议使用路由约束并保留默认的控制器选择器。对我不起作用。
目前我像这样提取控制器名称:
static string GetControllerName(IHttpRouteData route)
{
var controller = route.GetSubRoutes()
.Select(s => new
{
Name = ((HttpActionDescriptor[])s.Route.DataTokens.Single(t => t.Value is HttpActionDescriptor[]).Value)
.FirstOrDefault().ControllerDescriptor.ControllerName
}).FirstOrDefault();
return controller.Name;
}
对我来说似乎有点 hacky,但它可以工作并且不使用任何魔法常量(比如使用“actions”作为字典中的键进行搜索时)。
反正。在构建控制器列表(通过解析器),从请求中提取控制器名称并根据版本找到正确的 HttpControllerDescriptor 之后,我需要从 SelectController() 方法返回它。
这就是我得到 KeyNotFoundException 异常的地方。搜索后,我发现只有一次提到这一点(HttpControllerDispatcher 中的异常)
解决方案是在传入请求中填写正确的子路由数据。现在我还没有在互联网上找到关于这个或任何其他的官方提及。只有这个帖子。
我想出的是另一段骇人听闻的代码:
static void FillSubRoutes(IHttpRouteData route, string version)
{
var subroutes = route.GetSubRoutes()
.Where(s =>
((HttpActionDescriptor[])s.Route.DataTokens.Single(t => t.Value is HttpActionDescriptor[]).Value)
.Any(d => d.ControllerDescriptor.ControllerType.Namespace.EndsWith(version, StringComparison.OrdinalIgnoreCase)));
var values = route.Values.Single(v => v.Value is IHttpRouteData[]);
route.Values[values.Key] = subroutes.ToArray();
}
在我的情况下,最初一条路由有 4 个子路由(每个版本的控制器有 2 个)。这里发生的事情是我在最后部分的控制器命名空间中搜索具有特定版本的控制器描述符的子路由。在我的情况下,它总是 2 个(一个用于“GET”,一个用于“POST”请求,为简单起见,我在前面的控制器示例中省略了)。
所以最后我得到了我的问题:
- 是否有任何其他(最好更官方和适当的)方法从请求中提取控制器名称?
- 是否有任何其他(最好更正式和适当的)方法来解决 KeyNotFoundException 异常,如果我不填充子路由会发生这种情况?
- 当托管在 IIS 下时,所有这些都可以工作吗?