[ASP.NET Core MVC Pipeline] Routing Middleware — Custom IRouter

Middleware Pipeline - Routing
Middleware Pipeline

Why would I do that?

As previously said, the role of the IRouter in the pipeline is to evaluate the request and pass it to the IRouteHandler that is the best fit, but what might be mentioned is that you can also use the IRouter to make modifications to the incoming request. In this way, whenever you have a request that matches a certain criteria you can add, remove or edit some information and let the default RouteHandler do the rest.

The Basics

A bit different from the custom middleware, which is entirely implemented through conventions, the custom Router must implement an Interface called IRouter. This interface is quite simple:

namespace Microsoft.AspNetCore.Routing
{
public interface IRouter
{
VirtualPathData GetVirtualPath(VirtualPathContext context);
Task RouteAsync(RouteContext context);
}
}
public class CustomRouter : IRouter
{
private IRouter _defaultRouter;

public CustomRouter(IRouter defaultRouter)
{
_defaultRouter = defaultRouter;
}

public VirtualPathData GetVirtualPath(VirtualPathContext context)
{
return _defaultRouter.GetVirtualPath(context);
}

public Task RouteAsync(RouteContext context)
{
throw new NotImplementedException();
}
}

Routing our Requests

The concept behind the RouteAsync method is quite simple and straightforward, we do all the checking necessary to see if the provided route matches our IRouter context and, if it does, we execute the needed logic and inform the Routing middleware that the request has been handled.

public class CustomRouter : IRouter
{
private IRouter _defaultRouter;

public CustomRouter(IRouter defaultRouteHandler)
{
_defaultRouter = defaultRouteHandler;
}

public VirtualPathData GetVirtualPath(VirtualPathContext context)
{
return _defaultRouter.GetVirtualPath(context);
}

public async Task RouteAsync(RouteContext context)
{
var headers = context.HttpContext.Request.Headers;
var path = context.HttpContext.Request.Path.Value.Split('/');

// Look for the User-Agent Header and Check if the Request comes from a Mobile
if (headers.ContainsKey("User-Agent") &&
headers["User-Agent"].ToString().Contains("Mobile"))
{
var action = "Index";
var controller = "";
if (path.Length > 1)
{
controller = path[1];
if (path.Length > 2)
action = path[2];
}

context.RouteData.Values["controller"] = $"Mobile{controller}";
context.RouteData.Values["action"] = action;

await _defaultRouter.RouteAsync(context);
}
}
}

Hooking up to the Routing Middleware

Now we have a nice and functional Custom Router but if you run the application you will see that it is never touched by your request and that is because we never hooked our Router to the Routing Middleware.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseStaticFiles();

app.UseMvc(routes =>
{
routes.Routes.Add(new CustomRouter(routes.DefaultHandler));

routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Lucas Araujo | Azure Coder

Lucas Araujo | Azure Coder

Software Development and everything that encircles it :)