如何在ASP.NET Core中强制使用小写路由?

150
在ASP.NET 4中,这很容易实现,只需在应用程序的RegisterRoutes处理程序中使用routes.LowercaseUrls = true;即可。
我找不到在ASP.NET Core中实现此功能的等效方法。我认为它应该在这里:
app.UseMvc(configureRoutes =>
{
    configureRoutes.MapRoute("Default", "{controller=App}/{action=Index}/{id?}");
});

但是在 configureRoutes 中似乎没有任何允许它的内容... 除非文档中有我无法找到的扩展方法?

7个回答

327

对于 ASP.NET Core:

Startup 类的 ConfigureServices 方法中添加以下任意一行:

services.AddRouting(options => options.LowercaseUrls = true);
或者
services.Configure<RouteOptions>(options => options.LowercaseUrls = true); 

感谢Skorunka作为评论提供的答案。我认为它值得成为一个真正的答案。


50
值得注意的是,在实际调用 AddMvc() 方法之前,你应该将此代码放在 Startup.ConfigureServices() 方法中。AddRouting() 方法也会被 AddMvc() 调用,它使用了添加依赖项到服务集合中的方法的 Try 变体。因此,当它发现路由依赖项已经被添加时,它将跳过 AddMvc() 设置逻辑中的部分内容。 - Nick Albrecht
2
将这个标为正确答案,因为我的回答是在从ASP 4过渡到Core的时期。 - mariocatch
@NickAlbrecht,似乎在ASP.NET Core 5.0中无论是在之前还是之后调用它都没有影响。AddRouting()将被调用两次,所以顺序并不重要。 - Thomas Levesque
1
我相信这是在.NET Core 3.x左右完成的。他们将路由作为一个独立的功能而不是与MVC捆绑在一起进行了更改。我不认为现在从AddMvc(或者如果您不需要RazorPages,则从AddControllersWithViews)调用路由。因此,仅当您使用AspNetCore 2时,顺序才真正重要。(不记得在1.x中是否有此选项)。但是,他们确实将小写行为分成了两个设置,因此,如果您想要完全小写的地址,您需要将LowercaseUrlsLowercaseQueryStrings都设置为true - Nick Albrecht
1
你能澄清一下第二个选项是针对 Razor Pages,第一个选项是针对 MVC 吗? - carlin.scott
尽管这将生成小写的URL,但它不会强制小写URL。您仍然可以输入带有大写字符的URL。请参见此处,了解如何通过将任何大写URL重写为小写来强制执行小写URL。 - kimbaudi

68

ASP.NET Core版本更新至2.2及以上

ASP.NET Core 2.2开始,您可以使用ConstraintMap将您的路由设置为小写字母并使用破折号,这使得您的路由/Employee/EmployeeDetails/1变成了/employee/employee-details/1而不是/employee/employeedetails/1

要实现此功能,请先创建以下SlugifyParameterTransformer类:

public class SlugifyParameterTransformer : IOutboundParameterTransformer
{
    public string TransformOutbound(object value)
    {
        // Slugify value
        return value == null ? null : Regex.Replace(value.ToString(), "([a-z])([A-Z])", "$1-$2").ToLower();
    }
}

针对 ASP.NET Core 2.2 MVC:

Startup 类的 ConfigureServices 方法中:

services.AddRouting(option =>
{
    option.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer);
});

路由配置应如下所示:

app.UseMvc(routes =>
{
     routes.MapRoute(
        name: "default",
        template: "{controller:slugify}/{action:slugify}/{id?}",
        defaults: new { controller = "Home", action = "Index" });
});

对于ASP.NET Core 2.2 Web API:

Startup类的ConfigureServices方法中:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc(options => 
    {
        options.Conventions.Add(new RouteTokenTransformerConvention(new SlugifyParameterTransformer()));
    }).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

针对ASP.NET Core >=3.0的MVC:

Startup类的ConfigureServices方法中:

services.AddRouting(option =>
{
    option.ConstraintMap["slugify"] = typeof(SlugifyParameterTransformer);
});

路由配置应该如下所示:

app.UseEndpoints(endpoints =>
{
      endpoints.MapAreaControllerRoute(
          name: "AdminAreaRoute",
          areaName: "Admin",
          pattern: "admin/{controller:slugify=Dashboard}/{action:slugify=Index}/{id:slugify?}");

      endpoints.MapControllerRoute(
          name: "default",
          pattern: "{controller:slugify}/{action:slugify}/{id:slugify?}",
          defaults: new { controller = "Home", action = "Index" });
});

针对 ASP.NET Core >=3.0 的Web API:

Startup 类的 ConfigureServices 方法中:

services.AddControllers(options => 
{
    options.Conventions.Add(new RouteTokenTransformerConvention(new SlugifyParameterTransformer()));
});

对于ASP.NET Core >=3.0的Razor Pages:

Startup类的ConfigureServices方法中:

services.AddRazorPages(options => 
{
    options.Conventions.Add(new PageRouteTransformerConvention(new SlugifyParameterTransformer()));
})

这将使/Employee/EmployeeDetails/1路由到/employee/employee-details/1


我尝试了这段代码和官方的微软代码,但是“slugify”参数转换器没有任何效果。路由系统完全忽略它(因此URL未替换为虚线)。为了检查自己,我在TransformOutbound()方法中放置了记录器,但是没有从那里调用。 - Sam Alekseev
好的!请让我检查一下! - TanvirArjel
@user3172616 我现在已经检查过了!它按预期工作!例如生成路由为 employee-details。请问您能否向我展示您的配置? - TanvirArjel
@user3172616,你在测试的路由上使用了属性路由吗? - TanvirArjel
在你的代码中没有发现任何问题!不妨尝试将SlugifyParameterTransformer类从startup类中移除到其他地方? - TanvirArjel
显示剩余4条评论

27

正如其他回答所示,添加:

services.Configure<RouteOptions>(options => options.LowercaseUrls = true);

之前

services.AddMvc(...)

工作得很好,但我也想补充一点,如果你使用 Identity,你还需要:

services.AddIdentity<IdentityUser, IdentityRole>(options =>
{
    var appCookie = options.Cookies.ApplicationCookie;
    appCookie.LoginPath = appCookie.LoginPath.ToString().ToLowerInvariant();
    appCookie.LogoutPath = appCookie.LogoutPath.ToString().ToLowerInvariant();
    appCookie.ReturnUrlParameter = appCookie.ReturnUrlParameter.ToString().ToLowerInvariant();
});

如果需要,请显然地用您自己的类替换IdentityUserIdentityRole

我刚使用.NET Core SDK 1.0.4和1.0.5运行时进行了测试。


2
Configure<RouteOptions>() 是我个人认为最好的答案:简洁明了,一针见血(在 MVC Core 3.1 上测试通过)。 - T-moty

15

找到了解决方案。

在程序集中:Microsoft.AspNet.Routing 和命名空间 Microsoft.Extensions.DependencyInjection 中,你可以在你的 ConfigureServices(IServiceCollection services) 方法中实现这个:

services.ConfigureRouting(setupAction =>
{
    setupAction.LowercaseUrls = true;
});

18
对于 ASP NET MVC CORE:services.AddRouting(options => { options.LowercaseUrls = true; }); - Skorunka František
Microsoft.AspNetCore.Routing.dll 中的 Microsoft.Extensions.DependencyInjection - Skorunka František
4
RTM之前是正确的,现在您应该使用.AddRouting代替.ConfigureRouting。 - Yves Schelpe

8
值得注意的是,设置:
services.Configure<RouteOptions>(options => options.LowercaseUrls = true);

不影响查询字符串

为确保查询字符串也为小写,请将options.LowercaseQueryStrings设置为true

services.Configure<RouteOptions>(options => 
{ 
    options.LowercaseUrls = true; 
    options.LowercaseQueryStrings = true;
});

不过,将此属性设置为true仅在options.LowercaseUrls也为true时才相关。如果options.LowercaseUrlsfalse,则忽略options.LowercaseQueryStrings属性。


2

对于身份认证,@Jorge Yanes Diez的答案在ASP.NET Core 2.2我认为是2.x版本)中无效,因此如果您在使用Identity和ASP.NET Core 2.2(2.x),这里是解决方案:

services.ConfigureApplicationCookie(options =>
{
    options.LoginPath = "/account/login";
    options.ReturnUrlParameter = "returnurl";
    ...
});

参考文献: 配置ASP.NET Core身份验证


-1
我在RegisterRoutes :: RouteConfig中有这个:
routes.LowercaseUrls = true;

这是针对asp.net mvc 5的。 - Yaseer Arafat

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