Custom Routing in ASP.NET Core and MVC 6
Introduction:
Routing in ASP.NET allows us to map incoming requests with http handler. It also help us to generate links. The routing support was added in ASP.NET MVC first. Later, ASP.NET Webforms, ASP.NET Web API and SignalR also included routing support. Routing has been unified in ASP.NET Core to one implementation. A good overview of routing in ASP.NET Core can be found here. In this article, I will talk a little about custom routing in ASP.NET Core.
Description:
In ASP.NET MVC 5.x.x(or before) when you need to override the routing system then you will override RouteBase class or Route class. In ASP.NET Core, you need to override TemplateRoute or implement IRouter or INamedRouter. interace INamedRouter is IRouter plus Name property. Let's create a custom route which only allows requests with url starting with /home. ,
01 |
public
class
MyTemplateRoute : TemplateRoute
|
02 |
{
|
03 |
public
MyTemplateRoute(IRouter target, string
routeTemplate, IInlineConstraintResolver
inlineConstraintResolver)
|
04 |
: base(target,
|
05 |
routeTemplate,
|
06 |
inlineConstraintResolver:
inlineConstraintResolver)
|
07 |
{
|
08 |
}
|
09 |
10 |
public
MyTemplateRoute(IRouter target,
|
11 |
string
routeTemplate,
|
12 |
IDictionary<string, object> defaults,
|
13 |
IDictionary<string, object> constraints,
|
14 |
IInlineConstraintResolver
inlineConstraintResolver)
|
15 |
: base(target, routeTemplate, defaults,
constraints, inlineConstraintResolver)
|
16 |
{
|
17 |
}
|
18 |
19 |
public
MyTemplateRoute(IRouter target,
|
20 |
string
routeName,
|
21 |
string
routeTemplate,
|
22 |
IDictionary<string, object> defaults,
|
23 |
IDictionary<string, object> constraints,
|
24 |
IInlineConstraintResolver
inlineConstraintResolver)
|
25 |
: base(target, routeName, routeTemplate, defaults,
constraints, inlineConstraintResolver)
|
26 |
{ }
|
27 |
28 |
public
async override
Task RouteAsync(RouteContext context)
|
29 |
{
|
30 |
var requestPath =
context.HttpContext.Request.Path.Value ?? string.Empty;
|
31 |
if
(!requestPath.StartsWith("/home", StringComparison.OrdinalIgnoreCase))
|
32 |
{
|
33 |
return;
|
34 |
}
|
35 |
await base.RouteAsync(context);
|
36 |
}
|
37 |
}
|
First of all note that MyTemplateRoute class inherits from TemplateRoute class. Next, I have overridden the RouteAsync method where I simply check whether the url starts with /home or not. If not then return otherwise call the base RouteAsync. Dead simple. Isn't? You can directly use this class in the Startup class by adding routes.Routes.Add. But it will be look more nicer and consistent if we add an extension method,
01 |
public
static
class
RouteBuilderExtensions
|
02 |
{
|
03 |
public
static
IRouteBuilder MapRoute(this
IRouteBuilder routeCollectionBuilder,
|
04 |
string
name,
|
05 |
string
template)
|
06 |
{
|
07 |
MapMyCustomRoute(routeCollectionBuilder,
name, template, defaults: null);
|
08 |
return
routeCollectionBuilder;
|
09 |
}
|
10 |
11 |
public
static
IRouteBuilder MapMyCustomRoute(this
IRouteBuilder routeCollectionBuilder,
|
12 |
string
name,
|
13 |
string
template,
|
14 |
object
defaults)
|
15 |
{
|
16 |
return
MapMyCustomRoute(routeCollectionBuilder,
name, template, defaults, constraints: null);
|
17 |
}
|
18 |
19 |
public
static
IRouteBuilder MapMyCustomRoute(this
IRouteBuilder routeCollectionBuilder,
|
20 |
string
name,
|
21 |
string
template,
|
22 |
object
defaults,
|
23 |
object
constraints)
|
24 |
{
|
25 |
var inlineConstraintResolver =
routeCollectionBuilder
|
26 |
.ServiceProvider
|
27 |
.GetService<IInlineConstraintResolver>();
|
28 |
routeCollectionBuilder.Routes.Add(new
MyTemplateRoute(routeCollectionBuilder.DefaultHandler,
|
29 |
name,
|
30 |
template,
|
31 |
ObjectToDictionary(defaults),
|
32 |
ObjectToDictionary(constraints),
|
33 |
inlineConstraintResolver));
|
34 |
return
routeCollectionBuilder;
|
35 |
}
|
36 |
37 |
38 |
39 |
private
static
IDictionary<string, object> ObjectToDictionary(object
value)
|
40 |
{
|
41 |
var dictionary = value as
IDictionary<string, object>;
|
42 |
if
(dictionary != null)
|
43 |
{
|
44 |
return
dictionary;
|
45 |
}
|
46 |
47 |
return
new
RouteValueDictionary(value);
|
48 |
}
|
49 |
}
|
Finally, you can use this custom route inside the Startup.cs file,
1 |
routes.MapMyCustomRoute(
|
2 |
name: "default",
|
3 |
template: "{controller}/{action}/{id?}",
|
4 |
defaults: new
{ controller = "Home", action = "Index"
});
|
Now only the requests with /home urls accepted by the custom route. You can find another example of custom route (which implements the IRouter class) at github. You can find the routing repository of ASP.NEt Core at here.
Summary:
Custom routing in ASP.NET Core has been changed little bit. There are new classes/interfaces. In this article, I showed you how to create a custom route in ASP.NET Core.