How do you enforce lowercase routing in ASP.NET Core?
Asked Answered
B

7

157

In ASP.NET 4 this was as easy as routes.LowercaseUrls = true; in the RegisterRoutes handler for the app.

I cannot find an equivalent in ASP.NET Core for achieving this. I'd think it would be here:

app.UseMvc(configureRoutes =>
{
    configureRoutes.MapRoute("Default", "{controller=App}/{action=Index}/{id?}");
});

But nothing in configureRoutes looks to allow it... unless there's an extension method somewhere that I can't find in the docs perhaps?

Baton answered 1/4, 2016 at 14:20 Comment(0)
B
342

For ASP.NET Core:

Add one of the following lines to the ConfigureServices method of the Startup class:

services.AddRouting(options => options.LowercaseUrls = true);

or

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

Thanks to Skorunka for the answer as a comment. I thought it was worth promoting to an actual answer.

Bradfield answered 24/8, 2016 at 2:6 Comment(6)
It's worth noting you should put this BEFORE you actually call AddMvc() in your Startup.ConfigureServices() method. AddRouting() which is also called by AddMvc()uses the Try variants of the methods for adding dependencies to your service collection. So when it sees that the routing dependencies have already been added, it will skip that parts of AddMvc() setup logic.Greenwell
Switching this to correct answer since mine was during the transition of asp 4 to core.Baton
@NickAlbrecht it doesn't seem to make a difference if it's called before or after (as of ASP.NET Core 5.0, at least). AddRouting() will be called twice anyway, so it doesn't matter in which order.Arleanarlee
I believe that was done around .NET Core 3.x. They changed it so that routing was a stand alone feature instead of bundled with MVC. I don't believe routing is called from the AddMvc (or AddControllersWithViews if you don't need RazorPages) anymore. So the order only really matters if you're using AspNetCore 2. (Don't recall if this was an option in 1.x). However they did split the lowercase behavior into two settings, so if you want fully lower case addresses, you need to set both LowercaseUrls and LowercaseQueryStrings to true.Greenwell
Can you clarify that the 2nd option is for Razor Pages and first for MVC?Bixby
although this will generate lowercase urls, it will not enforce lowercase urls. you can still enter urls with uppercase characters. see this for how to enforce lowercase urls by rewriting any uppercase urls to lowercase.Itemized
I
73

Update in ASP.NET Core Version >= 2.2

From ASP.NET Core 2.2, along with lowercase you can also make your route dashed using ConstraintMap which will make your route /Employee/EmployeeDetails/1 to /employee/employee-details/1 instead of /employee/employeedetails/1.

To do so, first create the SlugifyParameterTransformer class should be as follows:

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();
    }
}

For ASP.NET Core 2.2 MVC:

In the ConfigureServices method of the Startup class:

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

And Route configuration should be as follows:

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

For ASP.NET Core 2.2 Web API:

In the ConfigureServices method of the Startup class:

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

For ASP.NET Core >=3.0 MVC:

In the ConfigureServices method of the Startup class:

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

And Route configuration should be as follows:

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" });
});

For ASP.NET Core >=3.0 Web API:

In the ConfigureServices method of the Startup class:

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

For ASP.NET Core >=3.0 Razor Pages:

In the ConfigureServices method of the Startup class:

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

This is will make /Employee/EmployeeDetails/1 route to /employee/employee-details/1

Involucrum answered 18/12, 2018 at 18:22 Comment(9)
I tried this code and official Microsoft code too, but "slugify" parameter transformer has no effect. It is just ignored by routing system (so URLs not replaced to dashed ones). To check myself i put logger into TransformOutbound() method, but no calls from there.Intumescence
Okay! Let me check please!Involucrum
@user3172616 I have check it right now! its working as expected! like generating route as employee-details. Would you show me your configuration please?Involucrum
@user3172616 are you using attribute routing on the route that you tested?Involucrum
I use standard routing approach (not attribute routing) on brand new core v2.2 solution in Visual Studio. There are two screenshots (c# code and .cshtml code). I tried to generate links in different ways with no effect. imgur.com/a/L8dCF6cIntumescence
Found nothing wrong in your code! Would give a try removing SlugifyParameterTransformer class from startup class to anywhere?Involucrum
I moved SlugifyParameterTransformer to separate *.cs file with no success. Generated urls are still the same like "/home/thisisthetest". Also i tried to throw random exception from there, it has no effect. But if i comment code line where i register this Transformer then app crashes because it uses unknown "slugify" placeholder in the route as expected.Intumescence
Sorry to hear that! Don't know what wrong happening in case of you while its working fine in my application.Involucrum
Let us continue this discussion in chat.Involucrum
A
27

As other answers indicate, adding:

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

before

services.AddMvc(...)

works great, but I also want to add that if you use Identity, you will also need:

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();
});

And obviously, replace both IdentityUser, and IdentityRole with your own classes if required.

I just tested this with .NET Core SDK 1.0.4 and the 1.0.5 runtime.

Angus answered 26/5, 2017 at 13:26 Comment(1)
Configure<RouteOptions>() is the best answer imho: tiny and straight to the point (tested on mvc core 3.1)Castleman
B
15

Found the solution.

In the assembly: Microsoft.AspNet.Routing, and the Microsoft.Extensions.DependencyInjection namespace, you can do this in your ConfigureServices(IServiceCollection services) method:

services.ConfigureRouting(setupAction =>
{
    setupAction.LowercaseUrls = true;
});
Baton answered 1/4, 2016 at 14:24 Comment(3)
For ASP NET MVC CORE: services.AddRouting(options => { options.LowercaseUrls = true; });Typographer
Microsoft.Extensions.DependencyInjection in Microsoft.AspNetCore.Routing.dllTypographer
This was true before RTM, now you should use .AddRouting in stead of .ConfigureRoutingHeartwarming
T
11

It is worth noting that setting:

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

does not affect query strings.

To ensure that query strings are also lowercase, set the options.LowercaseQueryStrings to true:

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

However, setting this property to true is only relevant if options.LowercaseUrls is also true. options.LowercaseQueryStrings property is ignored if options.LowercaseUrls is false.

Titre answered 6/8, 2021 at 11:31 Comment(0)
T
2

For identity, @Jorge Yanes Diez answer doesn't work in ASP.NET Core 2.2 (I think 2.x), so if you use Identity and ASP.NET Core 2.2 (2.x) here is the solution:

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

Ref: Configure ASP.NET Core Identity

Twink answered 9/1, 2019 at 19:54 Comment(0)
A
-1

I had this on RegisterRoutes::RouteConfig:

routes.LowercaseUrls = true;

Attainder answered 11/8, 2019 at 0:31 Comment(1)
It's for asp.net mvc 5Indigo

© 2022 - 2024 — McMap. All rights reserved.