# .NET Core MVC: regex routing with named groups

**Date:** 2018-02-19  
**Author:** Kees C. Bakker  
**Categories:** .NET / C#  
**Original:** https://keestalkstech.com/dotnet-core-mvc-regex-routing-with-named-groups/

![.NET Core MVC: regex routing with named groups](https://keestalkstech.com/wp-content/uploads/2018/02/chris-bair-419703.jpg)

---

Routing with regular expressions... to some the world would be a better place if everyone understood regular expressions. To others the world would be a better place *without* regular expressions at all. The thing is, they're easy to create, but hard to maintain. And every language has its own take on regex.
 One of the big advantages of the .Net implementation is *named* groups.  Today I want to show how to leverage named regular expression groups to build a routing constraint that will map each group value to a named route value.

## Friendly urls

At wehkamp we use the following friendly URLs to build a SEO-friendly navigation structure:

Let's assume we need to map these routing values into a parameter object:

```cs
class Parameter
{
    [FromRoute]
    public string CategoryCode { get; set; }
    [FromRoute]
    public string ShopCode { get; set; }
    [FromRoute]
    public string SegmentCode { get; set; }
    [FromRoute]
    public string ProductId { get; set; }
}
```

## Introducing a regex routing constraint

Routing constraints can be used to extract routing values from a URL. We could build a single constraint for every "type" of URL. Or... we could build a more generic constraint that will take an expression and use it as a source for parsing the routing values.

Here's our attempt:

```cs
public class RegexNamedGroupRoutingConstraint : IRouteConstraint
{
    private readonly List<Regex> regexes = new List<Regex>();

    public RegexNamedGroupRoutingConstraint(params string[] regexes)
    {
        foreach (var regex in regexes)
        {
            this.regexes.Add(new Regex(regex));
        }
    }

    public bool Match(HttpContext httpContext,
                      IRouter route,
                      string routeKey,
                      RouteValueDictionary values,
                      RouteDirection routeDirection)
    {
        if (values[routeKey] == null)
        {
            return false;
        }

        var url = values[routeKey].ToString();

        foreach (var regex in regexes)
        {
            var match = regex.Match(url);
            if (match.Success)
            {
                foreach (Group group in match.Groups)
                {
                    values.Add(group.Name, group.Value);
                }

                return true;
            }
        }

        return false;
    }
}
```

Note: we support multiple expression just to make things more readable. What we try to do can be done by a single expression, but it won't be very readable as it uses a lot of optional groups.

## Add it to the startup

Let's hook it up in the `Startup` class by adding the route to the `app.UseMvc`:

```cs
app.UseMvc(routes =>
{
    var shopRoutingConstraint = new RegexNamedGroupRoutingConstraint(
    "/(?<CategoryCode>[A-Z0-9]{3})_(?<ShopCode>[A-Z0-9]{3})_(?<SegmentCode>[A-Z0-9]{3})_(?<ProductId>\d+)/?$",
    "/(?<CategoryCode>[A-Z0-9]{3})_(?<ShopCode>[A-Z0-9]{3})_(?<SegmentCode>[A-Z0-9]{3})/?$",
    "/(?<CategoryCode>[A-Z0-9]{3})_(?<ShopCode>[A-Z0-9]{3})/?$",
    "/(?<CategoryCode>[A-Z0-9]{3})/?$");

    routes.MapRoute(
        name: "nav-by-codes",
        template: "{*url}",
        constraints: new { url = shopRoutingConstraint },
        defaults: new { controller = "Shop", action = "Detail" });
});
```

The important part is the `{*url}` template. This will use a [catch-all](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing#creating-routes) for the route. This will feed the *path* of the URL into the constraint (not the host nor the query-string).

## Summary

Regular expressions can be very useful in mapping routing values. The .Net routing engine will do the actual mapping. In this way you can build a nice routing convention with the `FromRoute` decoration on parameters and / or properties.
