【问题标题】:How to modify ASP NET Web API Route matching to allow parameters with slashes inside?如何修改 ASP NET Web API 路由匹配以允许内部带有斜杠的参数?
【发布时间】:2013-07-25 06:45:30
【问题描述】:

我们在后端使用 RavenDB,因此所有 DB 键都是包含正斜杠的字符串,例如users/1

AFAIK 没有办法使用默认的 ASP NET Web API 路由匹配引擎来匹配这样的参数,而不使用包罗万象,这意味着密钥必须是 URL 上的最后一件事。我尝试添加users/d+ 的正则表达式约束,但似乎没有什么区别,路由不匹配。

我必须替换哪些位才能进行足够的自定义路由匹配以实现这一点,最好不要破坏其余的路由匹配。例如,使用 url: "{*route}" 和进行完全正则表达式匹配的自定义约束可以工作,但可能会意外地与其他路由配置一起工作。

如果您的答案附带一些示例代码,那就更好了。

【问题讨论】:

  • 请再次阅读问题:without using a catch-all which means the key must be the last thing on the URL
  • 对不起 - 错过了。据我所知,这不能使用默认路由引擎来完成。你要么必须使用包罗万象,要么考虑编写自定义路由约束(但这仍然会使用包罗万象,但会给你更多的灵活性)
  • 正确的方法是覆盖 IHttpRoute 并在 GetRouteData 中进行处理,但它似乎永远不会被调用!请参阅aspnetwebstack.codeplex.com/discussions/451219 - 也许您有任何见解要分享。
  • 找到方法了!看我的回答。

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


【解决方案1】:

似乎可以通过定义自定义路由来做到这一点。在 MVC4(最后一个稳定版本 4.0.30506.0)中,无法按照规范实现 IHttpRoute,而是定义自定义 MVC 级别的 Route 并将其直接添加到 RouteTable。详情请参阅12。下面的RegexRoute 实现基于here 的实现,并带有来自答案here 的mod。

定义RegexRoute

public class RegexRoute : Route
{
    private readonly Regex urlRegex;

    public RegexRoute(string urlPattern, string routeTemplate, object defaults, object constraints = null)
        : base(routeTemplate, new RouteValueDictionary(defaults), new RouteValueDictionary(constraints), new RouteValueDictionary(), HttpControllerRouteHandler.Instance)
    {
        urlRegex = new Regex(urlPattern, RegexOptions.Compiled);
    }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        string requestUrl = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;

        Match match = urlRegex.Match(requestUrl);

        RouteData data = null;

        if (match.Success)
        {
            data = new RouteData(this, RouteHandler);

            // add defaults first
            if (null != Defaults)
            {
                foreach (var def in Defaults)
                {
                    data.Values[def.Key] = def.Value;
                }
            }

            // iterate matching groups
            for (int i = 1; i < match.Groups.Count; i++)
            {
                Group group = match.Groups[i];

                if (group.Success)
                {
                    string key = urlRegex.GroupNameFromNumber(i);

                    if (!String.IsNullOrEmpty(key) && !Char.IsNumber(key, 0)) // only consider named groups
                    {
                        data.Values[key] = group.Value;
                    }
                }
            }
        }

        return data;
    }
}

添加此DelegatingHandler 以避免由于其他错误导致NullReference

public class RouteByPassingHandler : DelegatingHandler
    {
        protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
        {
            HttpMessageInvoker invoker = new HttpMessageInvoker(new HttpControllerDispatcher(request.GetConfiguration()));
            return invoker.SendAsync(request, cancellationToken);
        }
    }

添加处理程序并直接路由到RouteTable

RouteTable.Routes.Add(new RegexRoute(@"^api/home/index/(?<id>\d+)$", "test", new { controller = "Home", action = "Index" }));

        config.MessageHandlers.Add(new RouteByPassingHandler());

瞧!

编辑:当 API 是自托管的(而不是使用 WebHost)时,此解决方案会出现问题,并且需要进一步的工作才能使其与两者一起使用。如果有人对此感兴趣,请发表评论,我会发布我的解决方案。

【讨论】:

    猜你喜欢
    • 2012-04-05
    • 2013-11-30
    • 2015-09-07
    • 1970-01-01
    • 1970-01-01
    • 2017-03-01
    • 2011-03-23
    • 2013-05-25
    • 1970-01-01
    相关资源
    最近更新 更多