首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >匹配路径相对路径

匹配路径相对路径
EN

Stack Overflow用户
提问于 2018-03-08 14:02:40
回答 1查看 1K关注 0票数 2

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

代码语言:javascript
运行
复制
public class TemplateController : Controller
{
    [Route("templates/{templateFilename}")]
    public ActionResult Index(string templateFilename)
    {
        ....
    }

}

,但引用此路由的链接是相对的

  • http://localhost/templates/t1 --工程
  • http://localhost/foo/bar/templates/t2 -中断(404)

我需要这样的东西:

代码语言:javascript
运行
复制
[Route("*/templates/{templateFilename}")]
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-03-08 16:53:04

您不能通过属性路由来完成这样的任务。只有通过实现IRouteConstraint或子类RouteBase才能进行高级路由匹配。

在本例中,子类RouteBase更简单。下面是一个示例:

代码语言:javascript
运行
复制
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;
    }
}

用法

代码语言:javascript
运行
复制
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:

代码语言:javascript
运行
复制
http://localhost/templates/t1
http://localhost/foo/bar/templates/t2

并将它们都发送到TemplateController.Index()方法中,最后一个段作为templateFilename参数。

注意:为了SEO目的,通常认为在多个URL上放置相同的内容并不是一个好的实践。如果这样做,建议使用标准标签通知搜索引擎哪些URL是权威的URL。

要在ASP.NET内核中完成相同的任务,请参见此

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49174973

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档