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?
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.
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
employee-details
. Would you show me your configuration please?
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.
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;
});
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
.
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
I had this on RegisterRoutes::RouteConfig:
routes.LowercaseUrls = true;
Success story sharing
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.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
.