【问题标题】:Ignore first segments in ASP.NET MVC Core routing忽略 ASP.NET MVC Core 路由中的第一段
【发布时间】:2018-02-27 15:33:07
【问题描述】:

我正在寻找能够匹配以下路线的路线定义:

  • /segment/xxxx/def
  • /segment/.../xxxx/def
  • /segment/that/can/span/xxxx/def

并且能够使用参数 `def 运行动作 xxxx

但是这种路线是不允许的:

[Route("/{*segment}/xxx/{myparam}")]

怎么做?

【问题讨论】:

  • catch-all 占位符不能位于路径模板末尾以外的任何位置。
  • 好的,但是怎么做呢?
  • 恩科西刚刚说你不能这样做
  • 没有其他选择?使用 IRouter 自定义路由?网址重写?正则表达式?我不知道

标签: asp.net-mvc routes .net-core url-routing asp.net-mvc-routing


【解决方案1】:

您可以使用自定义的IRouter 结合正则表达式来进行高级 URL 匹配,例如。

public class EndsWithRoute : IRouter
{
    private readonly Regex urlPattern;
    private readonly string controllerName;
    private readonly string actionName;
    private readonly string parameterName;
    private readonly IRouter handler;

    public EndsWithRoute(string controllerName, string actionName, string parameterName, IRouter handler)
    {
        if (string.IsNullOrWhiteSpace(controllerName))
            throw new ArgumentException($"'{nameof(controllerName)}' is required.");
        if (string.IsNullOrWhiteSpace(actionName))
            throw new ArgumentException($"'{nameof(actionName)}' is required.");
        if (string.IsNullOrWhiteSpace(parameterName))
            throw new ArgumentException($"'{nameof(parameterName)}' is required.");
        this.controllerName = controllerName;
        this.actionName = actionName;
        this.parameterName = parameterName;
        this.handler = handler ??
            throw new ArgumentNullException(nameof(handler));
        this.urlPattern = new Regex($"{actionName}/[^/]+/?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
    }

    public VirtualPathData GetVirtualPath(VirtualPathContext context)
    {
        var controller = context.Values.GetValueOrDefault("controller") as string;
        var action = context.Values.GetValueOrDefault("action") as string;
        var param = context.Values.GetValueOrDefault(parameterName) as string;

        if (controller == controllerName && action == actionName && !string.IsNullOrEmpty(param))
        {
            return new VirtualPathData(this, $"{actionName}/{param}".ToLowerInvariant());
        }
        return null;
    }

    public async Task RouteAsync(RouteContext context)
    {
        var path = context.HttpContext.Request.Path.ToString();

        // Check if the URL pattern matches
        if (!urlPattern.IsMatch(path, 1))
            return;

        // Get the value of the last segment
        var param = path.Split('/').Last();

        //Invoke MVC controller/action
        var routeData = context.RouteData;

        routeData.Values["controller"] = controllerName;
        routeData.Values["action"] = actionName;
        // Putting the myParam value into route values makes it
        // available to the model binder and to action method parameters.
        routeData.Values[parameterName] = param;

        await handler.RouteAsync(context);
    }
}

用法

app.UseMvc(routes =>
{
    routes.Routes.Add(new EndsWithRoute(
        controllerName: "Home", 
        actionName: "About", 
        parameterName: "myParam", 
        handler: routes.DefaultHandler));

    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

这个路由是参数化的,允许你传入与被调用的动作方法相对应的控制器、动作和参数名称。

public class HomeController : Controller
{
    public IActionResult About(string myParam)
    {
        ViewData["Message"] = "Your application description page.";

        return View();
    }
}

要使其匹配任何操作方法名称并能够使用该操作方法名称再次构建 URL,还需要做更多的工作。但这条路线将允许您通过多次注册来添加其他操作名称。

注意:出于 SEO 的目的,将相同的内容放在多个 URL 上通常不是一种好的做法。如果您这样做,建议使用canonical tag 通知搜索引擎哪个网址是权威的

See this to accomplish the same in ASP.NET MVC (prior to ASP.NET Core).

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-25
    • 1970-01-01
    • 2019-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多