ASP.NET Web API v2中的后备控制器路由 [英] Fallback controller route in ASP.NET Web API v2

查看:78
本文介绍了ASP.NET Web API v2中的后备控制器路由的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个脱机Web应用程序,该应用程序将路径字符串用于客户端URL.

I'm building an offline web app that uses the path string for client-side URLs.

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

There are several (attribute-based) routes that map to dedicated controllers for resources, API calls, etc.. For example:

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

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

I then want all requests that do not match one of these patterns to be routed to my bootstrap HTML page, which I currently serve via a dedicated controller. So, for example, the following requests need to end up at the bootstrap HTML page:

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

我正在使用OWIN,因此从理论上讲,我可以使用某种自定义的后备"处理程序来执行此操作.但是,我很重视通过Web API框架免费获得的功能.

I'm using OWIN, so theoretically I could probably do this with a custom "fallback" handler of some kind. However, I value the functionality that I get for free with the Web API framework.

我还应该提到,Web API已经在OWIN映射的"/myapp"子路径下注册,因此该路径的第一部分将不会在Web API路由中看到.另外,我想尽可能地继续使用基于属性的路由,以提高可读性.

I should also mention that Web API is already registered under an OWIN-mapped subpath of "/myapp", so that first part of the path will not be seen in the Web API routes. Also, I would like to keep using attribute-based routing if possible, for readability.

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

The solution I'm envisioning is something like this:

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()的路由甚至无法正常工作.
  1. A request for /myapp/api or /myapp/resources fails with a 500 error because there are multiple matching controller types. I know that routes can be given a priority within a controller, and I guess I was hoping that the route priority would also hold across different controllers. But that was admittedly a shot in the dark.
  2. Requests for myapp/customers/ and myapp/orders/today fail with a 404 error, so apparently my route for BootstrapController.Index() is not even working correctly.

唯一有效的请求是/myapp,该请求正确返回200即可返回"bootstrap".

The only request that works is /myapp, which correctly returns "bootstrap" with a 200 OK.

我对Web API的工作方式了解不足,无法解决此问题.希望这里有人可以提供帮助!

I don't know enough about how Web API works to be able to solve this problem. Hopefully someone here can help!

推荐答案

经过更多研究指导的反复试验后,我想出了一个解决方案.它不允许我在BootstrapController上使用基于属性的路由,这没什么大不了的,因为这是特例.

After some more research-guided trial-and-error, I figured out a solution. It doesn't allow me to use attribute-based routing on the BootstrapController, which is not a big deal since it's a special case.

以下是必要的更改:

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也需要在没有路由属性的情况下进行重写:

The BootstrapController also needs to be rewritten without routing attributes:

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

事后看来,这总是很明显的. :P我没有意识到的是,可以通过将路由表与基于属性的路由结合使用来解决多个匹配路由"问题.然后,只需弄清楚如何使路线条目与任何深度的子路径匹配即可.

It's always obvious in hindsight. :P What I didn't realize was that the "multiple matching routes" problem could be circumvented by using the routing table in combination with attribute-based routes. Then it was just a matter of figuring out how to make the route entry match a subpath of any depth.

这篇关于ASP.NET Web API v2中的后备控制器路由的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆