【问题标题】:Performing Explicit Route Mapping based upon Web Api v2 Attributes基于 Web Api v2 属性执行显式路由映射
【发布时间】:2013-10-31 02:30:14
【问题描述】:

我正在升级一个自定义解决方案,我可以在其中动态注册和取消注册 Web Api 控制器以使用新的属性路由机制。但是,最近对 RTM 的更新似乎破坏了我的解决方案。

我的解决方案公开了几个用于管理目的的 Web Api 控制器。这些是使用新的 HttpConfigurationExtensions.MapHttpAttributeRoutes 方法调用注册的。

该解决方案还允许 Web Api 控制器托管在第三方程序集中并动态注册。在这个阶段,一旦加载了第三方控制器,再次调用 HttpConfigurationExtensions.MapHttAttributeRoutes 将引发异常。因此,我的方案使用反射来检查 RoutePrefix 和 Route 属性,并在 HttpConfiguration 对象上注册相应的路由。

很遗憾,调用 Web Api 会导致以下错误:

“未找到与请求 URI 匹配的 HTTP 资源”。

这是一个我想使用的简单控制器:

[RoutePrefix("api/ze")]
public sealed class ZeController : ApiController
{
    [HttpGet]
    [Route("one")]
    public string GetOne()
    {
        return "One";
    }

    [HttpGet]
    [Route("two")]
    public string GetTwo()
    {
        return "Two";
    }

    [HttpPost]
    [Route("one")]
    public string SetOne(string value)
    {
        return String.Empty;
    }
}

这是我尝试的第一个解决方案:

configuration.Routes.MapHttpRoute("ZeApi", "api/ze/{action}");

这是我尝试的第二个解决方案:

var type = typeof(ZeController);
var routeMembers = type.GetMethods().Where(m => m.IsPublic);
foreach (MethodInfo method in routeMembers)
{
        var routeAttribute = method.GetCustomAttributes(false).OfType<RouteAttribute>().FirstOrDefault();
       if (routeAttribute != null)
        {
           string controllerName = type.Name.Substring(0, type.Name.LastIndexOf("Controller"));
           string routeTemplate = string.Join("/", "api/Ze", routeAttribute.Template);
           configuration.Routes.MapHttpRoute(method.Name, routeTemplate);
       }
}

我还尝试了第三种解决方案,我创建了实现 IHttpRoute 的自定义类,并尝试将它们注册到配置中,但无济于事。

是否可以根据新路由属性中包含的信息使用旧式路由映射?

更新

我已在 Web 应用程序中安装了我的控制器,以便使用 Web Api Route Debugger 对路由选择过程进行故障排除。这是截图的结果:

如您所见,似乎选择了正确的操作,但我仍然收到 404 错误。

更新2

经过进一步分析,并根据 Kiran Challa 在下面的评论,似乎 Web Api 的设计阻止了混合属性路由和常规路由,而我想要做的事情是不可能使用这种方法的。

我创建了一个自定义属性 [RouteEx],它与 Web Api [Route] 属性的用途相同,现在我的代码可以完美运行。

我想,由于使用传统的属性路由是不可能的,所以关于这个问题的答案都不能合法地被认为是有效的。所以我还没有提名答案。

【问题讨论】:

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


    【解决方案1】:

    不应要求您自己使用反射并检查基于属性路由的属性。属性路由使用现有的 Web API 功能来获取要扫描的控制器列表。

    问题:在切换到属性路由之前,您是如何加载这些具有 控制器?

    如果您是通过IAssembliesResolver 服务执行此操作,那么即使使用属性路由,此解决方案也应该可以工作,您不需要做任何额外的事情。

    关于你的更新:你打电话给MapHttpAttributeRoutes吗?

    【讨论】:

    • 我确实在使用 MapHttpAttributeRoutes,这对于我的解决方案中内置的控制器来说非常有效。我不能再次为第三方插件控制器调用 MapHttpAttributeRoutes,因为它会引发异常。所以我需要为这些额外的控制器使用反射。
    • 您如何将第三方插件控制器加载到您的应用程序中...您是否有 IAssembliesResolver 的自定义实现?
    • 不,我不这样做,因为我发现 IAssembliesResolver 只使用一次(在第一个请求上)并且结果由 WebApi 框架缓存。因此,我在自定义实现 IHttpControllerSelector 中进行程序集解析和控制器选择。
    • 经过进一步分析,发现使用[Route]属性是该方案不起作用的原因。如果我创建一个自定义 [RouteEx] 属性并对此执行反射,它可以正常工作。我跟踪到框架中的 ApiControllerActionSelector 类的错误:如果属性实现了 IHttpRouteInfoProvider(Route 属性执行此操作):相应的操作不被视为当前请求的有效候选者。
    • 有趣的场景。因此,在配置已经初始化并且收到请求时,您正在动态加载程序集。想知道为什么您不能使用程序集解析器一次加载程序集?关于您的最新评论,该设计是经过深思熟虑的,因为传统路线无法到达属性路线。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-05
    • 2015-08-11
    • 2017-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多