相对于路径匹配路线 [英] Match route relative to path

查看:150
本文介绍了相对于路径匹配路线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望任何以 / templates / {filename} 结尾的URL都可以使用route属性(例如:

I want any URL that ends with /templates/{filename} to map to a specific controller using either a route attribute i.e. something like:

public class TemplateController : Controller
{
    [Route("templates/{templateFilename}")]
    public ActionResult Index(string templateFilename)
    {
        ....
    }

}

可行,但是引用此路线的链接是相对的

which works, but the links referencing this route are relative so


  • http:// localhost / templates / t1 -有效

  • http:// localhost / foo / bar / templates / t2 -休息(404)

  • http://localhost/templates/t1 -- works
  • http://localhost/foo/bar/templates/t2 -- breaks (404)

我需要类似的东西:

[Route("*/templates/{templateFilename}")]


推荐答案

使用属性路由无法完成类似的任务。只有通过实现 IRouteConstraint 或子类 RouteBase 来进行高级路由匹配。

You cannot accomplish something like this with attribute routing. It is only possible to do advanced route matching by implementing IRouteConstraint or subclassing RouteBase.

在这种情况下,将 RouteBase 子类化更为简单。下面是一个示例:

In this case, it is simpler to subclass RouteBase. Here is an example:

public class EndsWithRoute : RouteBase
{
    private readonly Regex urlPattern;
    private readonly string controllerName;
    private readonly string actionName;
    private readonly string prefixName;
    private readonly string parameterName;

    public EndsWithRoute(string controllerName, string actionName, string prefixName, string parameterName)
    {
        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(prefixName))
            throw new ArgumentException($"'{nameof(prefixName)}' is required.");
        if (string.IsNullOrWhiteSpace(parameterName))
            throw new ArgumentException($"'{nameof(parameterName)}' is required.");

        this.controllerName = controllerName;
        this.actionName = actionName;
        this.prefixName = prefixName;
        this.parameterName = parameterName;
        this.urlPattern = new Regex($"{prefixName}/[^/]+/?$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
    }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        var path = httpContext.Request.Path;

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

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

        var routeData = new RouteData(this, new MvcRouteHandler());

        //Invoke MVC controller/action
        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;

        return routeData;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        object controllerObj;
        object actionObj;
        object parameterObj;

        values.TryGetValue("controller", out controllerObj);
        values.TryGetValue("action", out actionObj);
        values.TryGetValue(parameterName, out parameterObj);

        if (controllerName.Equals(controllerObj.ToString(), StringComparison.OrdinalIgnoreCase) 
            && actionName.Equals(actionObj.ToString(), StringComparison.OrdinalIgnoreCase)
            && !string.IsNullOrEmpty(parameterObj.ToString()))
        {
            return new VirtualPathData(this, $"{prefixName}/{parameterObj.ToString()}".ToLowerInvariant());
        }
        return null;
    }
}



用法



Usage

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.Add(new EndsWithRoute(
            controllerName: "Template",
            actionName: "Index",
            prefixName: "templates",
            parameterName: "templateFilename"));

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

这将与以下URL匹配:

This will match these URLs:

http://localhost/templates/t1
http://localhost/foo/bar/templates/t2

并将它们都发送到 TemplateController.Index()方法


注意:<$ templateFilename 参数。

在ASP.NET Core中,请参见此处实现相同的操作

这篇关于相对于路径匹配路线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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