在每个URL末尾添加一个斜杠?

30

我这里有一个小问题。我需要在我正在处理的网站中,在每个URL的末尾添加一个斜杠。我定义了网站内的所有链接都以斜杠结尾,例如:

<a href="/register/">Register</a>

虽然这样做运行得很好,但仍有一个小问题:调用RedirectToAction()生成的URL存在问题。例如:

return RedirectToAction("Register", "Users");

这将导致URL更改为/register,没有尾随斜杠。我已修改我的路由系统如下:

  routes.MapRoute("register",
                        "register/",
                        new {controller = "Users", action = "Register"}
            );

仍然没有自动添加所需的尾部斜杠!
我查看了这个问题和这个问题,但由于我没有使用任何URL重写库,它们完全不同于我正在使用的asp.net MVC路由系统。
那么你们认为怎么样?


1
对于任何想了解如何在ASP.NET Core中执行此操作的人,请使用services.Configure<RouteOptions>(routeOptions => { routeOptions.AppendTrailingSlash = true;};,其中services是一个IServiceCollection - Ahmed
为了访问“RouteOptions”,请确保使用“Microsoft.AspNetCore.Routing;”。 - AJ Venturella
6个回答

50

现在 RouteCollection 类有一个 AppendTrailingSlash 布尔值,您可以将其设置为 true 以获得此行为。


9
AppendTrailingSlash函数不会重写路由。 - sk904861

21

您可以创建一个新的 Route,覆盖 GetVirtualPath 方法。在此方法中,将斜线添加到 VirtualPath 后面。像这样:

public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
     VirtualPathData path = base.GetVirtualPath(requestContext, values);

     if (path != null)
         path.VirtualPath = path.VirtualPath + "/";
     return path;
}

为了简洁起见,我将整个示例发布在CodePaste.net上。

现在,您只需使用routes.MapRouteTrailingSlash()而不是routes.MapRoute()来注册路由即可。

routes.MapRouteTrailingSlash("register",
                             "register",
                             new {controller = "Users", action = "Register"}
);

当调用GetVirtualPath()时,该路由将会向路径添加一个斜杠,这是RedirectToAction()所做的。

更新:由于CodePaste链接失效,这里提供完整代码:

public class TrailingSlashRoute : Route {
    public TrailingSlashRoute(string url, IRouteHandler routeHandler)
        : base(url, routeHandler) {}

    public TrailingSlashRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
        : base(url, defaults, routeHandler) {}

    public TrailingSlashRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints,
                          IRouteHandler routeHandler)
        : base(url, defaults, constraints, routeHandler) {}

    public TrailingSlashRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints,
                          RouteValueDictionary dataTokens, IRouteHandler routeHandler)
        : base(url, defaults, constraints, dataTokens, routeHandler) {}

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) {
        VirtualPathData path = base.GetVirtualPath(requestContext, values);

        if (path != null)
            path.VirtualPath = path.VirtualPath + "/";
        return path;
    }
}

public static class RouteCollectionExtensions {
    public static void MapRouteTrailingSlash(this RouteCollection routes, string name, string url, object defaults) {
        routes.MapRouteTrailingSlash(name, url, defaults, null);
    }

    public static void MapRouteTrailingSlash(this RouteCollection routes, string name, string url, object defaults,
                                         object constraints) {
        if (routes == null)
            throw new ArgumentNullException("routes");

        if (url == null)
            throw new ArgumentNullException("url");

        var route = new TrailingSlashRoute(url, new MvcRouteHandler())
                    {
                        Defaults = new RouteValueDictionary(defaults),
                        Constraints = new RouteValueDictionary(constraints)
                    };

        if (String.IsNullOrEmpty(name))
            routes.Add(route);
        else
            routes.Add(name, route);
    }
}

CodePaste.net的链接已经过期了。有重新发布的机会吗? - whit537
我真的很想看到你提到的整个示例代码。不幸的是,你的链接已经失效了 :( 你能否提供另一个链接,这样我就可以看到你的示例代码吗? - marcusstarnes
4
已在帖子中添加了代码。希望可以帮到您!抱歉链接失效了。 - aolde
非常感谢您。这让我免于重写大量表单的麻烦! - Dave Thieben
1
-1 当URL包含查询字符串时,这将无法工作。斜杠将被放置在查询字符串之后。 - Craig Bovis
如何指定命名空间? - Muhamad Jafarnejad

5

很好的干净解决方案,codingbug!

我遇到的唯一问题是MVC3中主页的双重尾部斜杠。

Razor示例:

@Html.ActionLink("Home", "Index", "Home")

相关链接:
http://mysite.com//

为了解决这个问题,我调整了GetVirtualPath的覆盖:

public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{       
    VirtualPathData path = base.GetVirtualPath(requestContext, values);       

    if (path != null && path.VirtualPath != "")       
        path.VirtualPath = path.VirtualPath + "/";       
    return path;       
}

3

codingbug提供的解决方案非常好。我需要一个非常类似的解决方案,但只适用于我的根URL。我知道这可能存在问题,但这是我所做的。在所有环境中似乎都可以正常工作。我认为它也有效,因为只有当用户第一次访问我们的主页时,才不需要训练斜杠。那就是我想避免的情况。如果这是你想要避免的情况,那么这个方法适合你。

  public class HomeController : Controller
  {
    public ActionResult Index()
    {
      if (!Request.RawUrl.Contains("Index") && !Request.RawUrl.EndsWith("/"))
        return RedirectToAction("Index", "Home", new { Area = "" });

如果需要更多,我可能会使用codingbug提供的代码。但目前为止,我喜欢保持简单。

注意:我期望Home\Index从URL中被路由引擎移除。


1
这是一些MVC控制器代码,展示了我如何在一个非常简单的get请求中实现它。
public ActionResult Orders()
{
    if (!Request.Path.EndsWith("/"))
    {
        return RedirectPermanent(Request.Url.ToString() + "/");
    }
    return View();
}

1
我找到了一个比最受赞同的答案更简单的解决方案。
routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}/", <-- trailing slash here
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );

这将在所有情况下作为尾随斜杠"/"的作用。

1
不会的。如果您按照这种方式操作,然后使用RouteUrl("{路由名称}",new RouteValueDictionary({参数}))生成URL,那么尾随斜杠将被切掉。 - Przemo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接