question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

RegexRouteConstraint should use Compiled Regex

See original GitHub issue

Today, when using a regex route constraint, we create a new Regex:

https://github.com/dotnet/aspnetcore/blob/e5238763bddd7100823751c4a4ae0220d78160aa/src/Http/Routing/src/Constraints/RegexRouteConstraint.cs#L40-L43

This should use the RegexOptions.Compiled as well. That way we aren’t interpreting these regular expressions every time the route is inspected.

Our docs even say this should be using Compiled:

The ASP.NET Core framework adds RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant to the regular expression constructor. See RegexOptions for a description of these members.

Issue Analytics

  • State:closed
  • Created 8 months ago
  • Comments:20 (20 by maintainers)

github_iconTop GitHub Comments

1reaction
JamesNKcommented, Jan 30, 2023

@surayya-MS From the discussion in our call, here is an example of configuring the regex route to go back to the old behavior:

public class NonCompiledRegexInlineRouteConstraint : RegexRouteConstraint
{
    public NonCompiledRegexInlineRouteConstraint(string regexPattern)
        : base(new Regex(regexPattern, RegexOptions.CultureInvariant | RegexOptions.IgnoreCase))
    {
    }
}

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRouting(options =>
{
    options.ConstraintMap["regex"] = typeof(NonCompiledRegexInlineRouteConstraint);
});

This is the escape hatch we can recommend to customers if, even after improvements, their app has problems with compiled regexes.

1reaction
JamesNKcommented, Jan 30, 2023

Test app with 30,000 regex routes:

using System.Diagnostics;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (HttpContext context, Func<Task> next) =>
{
    Console.WriteLine("Start time");
    Stopwatch stopwatch = Stopwatch.StartNew();

    await next();

    stopwatch.Stop();
    Console.WriteLine(stopwatch.Elapsed.TotalSeconds);
});

app.UseRouting();

Task Plaintext(HttpContext context) => context.Response.WriteAsync("Hello, World!");
for (int i = 0; i < 30_000; i++)
{
    var url = "/plaintext/nested" + i + "/{riskId:regex(^\\d{{7}}|(SI[[PG]]|JPA|DEM)\\d{{4}})}";
    app.MapGet(url, Plaintext);
}

app.MapGet("/", (HttpContext context) =>
{
    return context.Response.WriteAsync("Hello world");
});

Console.WriteLine("Running app");
app.Run();

Time to first request:

  • Compiled regex - 1.996s (new)
  • Interpreted regex - 0.9421s (old)
  • No regex - 0.5757s

App memory usage:

  • Compiled regex - 865mb (new)
  • Interpreted regex - 385mb (old)
  • No regex - 280mb

I think we should:

  • Make the constraint store the regex string and make Regex construction lazy until needed.
  • Add a cache to DFA builder to share regex instances.

That will bring first request and memory usage down to “no regex” results for most apps. We get our cake and eat it too: improved startup performance and regex per-request performance.

There still might be some edge-case apps out there that perform worst. They have lots of unique regex routes, and they all get visited, and memory usage is a problem. Routing is configurable so we can advise them to configure the regex constraint with an implementation that doesn’t call RegexOptions.Compiled.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Is it bad to use regex based route constraints?
I have the following route that will be hit extensively on my ASP.NET MVC website: routes.MapRoute( null, "products/{ProductID}/{SeoName}", new ...
Read more >
Using source-generated regex in ASP.NET Core route ...
In this post, I describe how to use source-generated regex in ASP.NET Core routing to improve startup time.
Read more >
Best Practices for Regular Expressions in .NET
You should use compiled regular expressions when you call regular expression methods with a specific regular expression relatively ...
Read more >
Compilation and Reuse in Regular Expressions
You can compile all of your expressions into a reusable DLL by using the CompileToAssembly method. This avoids the need to compile at...
Read more >
To Compile or Not To Compile
I noticed that I had sort of mindlessly added RegexOptions.Compiled all over the place. It says "compiled" so it must be faster, right?...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found