ASP.NET Web API v2中的后备控制器路由

时间:2014-07-03 22:11:55

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

我正在构建一个使用客户端网址的路径字符串的离线网络应用。

有几个(基于属性的)路由映射到专用控制器以获取资源,API调用等。例如:

/myapp/api/...
/myapp/resources/...

然后我希望所有与这些模式之一不匹配的请求被路由到我的引导程序HTML页面,我目前通过专用控制器提供该页面。因此,例如,以下请求需要在引导HTML页面结束:

/myapp/customers/...
/myapp/orders/...
/myapp/
/myapp/<anything that doesn't start with another controller's route prefix>

我使用OWIN,所以从理论上讲,我可以通过自定义&#34;后备&#34;某种处理程序。但是,我重视使用Web API框架免费获得的功能。

我还应该提到Web API已经在&#34; / myapp&#34;的OWIN映射子路径下注册,因此在Web API路由中将看不到路径的第一部分。此外,为了便于阅读,我希望尽可能继续使用基于属性的路由。

我想象的解决方案是这样的:

using Microsoft.Owin;
using Owin;
using System;
using System.Web.Http;

[assembly: OwinStartup(typeof(MyApp.Startup))]

namespace MyApp
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.Map("/myapp", myApp =>
            {
                var configuration = new HttpConfiguration();
                configuration.MapHttpAttributeRoutes();
                configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
                myApp.UseWebApi(configuration);
            });
        }
    }

    [RoutePrefix("api")]
    public class MyApiController : ApiController
    {
        [HttpGet, Route("")] // GET: myapp/api
        public string Api() { return "api"; }
    }

    [RoutePrefix("resources")]
    public class ResourcesController : ApiController
    {
        [HttpGet, Route("")] // GET: myapp/resources
        public string Resources() { return "resources"; }
    }

    [RoutePrefix("")]
    public class BootstrapController : ApiController
    {
        [HttpGet, Route("{subpath:regex(^.*$)?}", // GET: myapp/...
            Name = "BootstrapPage", Order = Int32.MaxValue)]
        public string Index(string subpath = "") { return "bootstrap"; }
    }
}

此设置存在两个问题:

  1. /myapp/api/myapp/resources的请求因500个错误而失败,因为有多个匹配的控制器类型。我知道路由可以在控制器中给予优先级,我想我希望路由优先级也可以在不同的控制器中保持。但这无疑是在黑暗中拍摄的。
  2. myapp/customers/myapp/orders/today的请求因404错误而失败,显然我的BootstrapController.Index()路由甚至无法正常工作。
  3. 唯一有效的请求是/myapp,它正确返回&#34; bootstrap&#34; 200 OK。

    我不太了解Web API如何解决此问题。希望有人可以提供帮助!

1 个答案:

答案 0 :(得分:3)

经过一些研究指导的反复试验,我找到了解决方案。它不允许我在BootstrapController上使用基于属性的路由,这不是什么大问题,因为它是一个特例。

以下是必要的更改:

app.Map("/myapp", myApp =>
{
    var configuration = new HttpConfiguration();
    configuration.MapHttpAttributeRoutes();
    configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;

    configuration.Routes.MapHttpRoute(
        name: "BootstrapPage",
        routeTemplate: "{*subpath}",
        defaults: new { controller = "Bootstrap", action = "Index", subpath = RouteParameter.Optional });

    myApp.UseWebApi(configuration);
});

还需要在没有路由属性的情况下重写BootstrapController:

public class BootstrapController : ApiController
{
    [HttpGet]
    public string Index() { return "bootstrap"; }
}

后见之明总是显而易见的。 :P我没有意识到的是,通过将路由表与基于属性的路由结合使用,可以避免“多个匹配路由”问题。然后,只需要弄清楚如何使路线入口匹配任何深度的子路径。