How do you enforce lowercase routing in ASP.NET Core?
Solution 1
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.
Solution 2
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
Solution 3
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.
Solution 4
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;
});
Solution 5
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
.
mariocatch
Updated on August 10, 2021Comments
-
mariocatch almost 3 years
In ASP.NET 4 this was as easy as
routes.LowercaseUrls = true;
in theRegisterRoutes
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? -
Skorunka František almost 8 yearsFor ASP NET MVC CORE: services.AddRouting(options => { options.LowercaseUrls = true; });
-
Skorunka František almost 8 yearsMicrosoft.Extensions.DependencyInjection in Microsoft.AspNetCore.Routing.dll
-
Yves Schelpe over 7 yearsThis was true before RTM, now you should use .AddRouting in stead of .ConfigureRouting
-
Nick Albrecht over 7 yearsIt's worth noting you should put this BEFORE you actually call
AddMvc()
in yourStartup.ConfigureServices()
method.AddRouting()
which is also called byAddMvc()
uses theTry
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 ofAddMvc()
setup logic. -
mariocatch about 7 yearsSwitching this to correct answer since mine was during the transition of asp 4 to core.
-
Sam Alekseev over 5 yearsI 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.
-
TanvirArjel over 5 yearsOkay! Let me check please!
-
TanvirArjel over 5 years@user3172616 I have check it right now! its working as expected! like generating route as
employee-details
. Would you show me your configuration please? -
TanvirArjel over 5 years@user3172616 are you using attribute routing on the route that you tested?
-
Sam Alekseev over 5 yearsI 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/L8dCF6c
-
TanvirArjel over 5 yearsFound nothing wrong in your code! Would give a try removing
SlugifyParameterTransformer
class fromstartup
class to anywhere? -
Sam Alekseev over 5 yearsI 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.
-
TanvirArjel over 5 yearsSorry to hear that! Don't know what wrong happening in case of you while its working fine in my application.
-
TanvirArjel over 5 yearsLet us continue this discussion in chat.
-
T-moty about 4 yearsConfigure<RouteOptions>() is the best answer imho: tiny and straight to the point (tested on mvc core 3.1)
-
Thomas Levesque over 3 years@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.
-
Nick Albrecht over 3 yearsI 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
(orAddControllersWithViews
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 bothLowercaseUrls
andLowercaseQueryStrings
totrue
. -
Yaseer Arafat about 3 yearsIt's for asp.net mvc 5
-
carlin.scott over 2 yearsCan you clarify that the 2nd option is for Razor Pages and first for MVC?