How To Force All URLs To Lowercase in ASP.NET Core and ASP.NET



Last updated: October 28th, 2026

Updated October 2026: code is now inline and tested on .NET 8 and .NET 10. The redirect rule now skips POST requests and handles PathBase, and the IIS rule has been corrected.

Quick Answer

ASP.NET Core routing is case-insensitive by default: /About, /about and /ABOUT all reach the same action. That is convenient for users but creates duplicate URLs for search engines. Fix it in two parts:

  1. Generated URLs: set RouteOptions.LowercaseUrls = true so every link ASP.NET Core builds is lowercase.
  2. Incoming URLs: 301-redirect any request whose path contains uppercase letters to the lowercase version.

Examples:

  • Generated URL: Url.Action("Login", "Account") resolves to /account/login instead of /Account/Login.
  • Incoming request: https://mysite.com/MyPage redirects (301) to https://mysite.com/mypage.

ASP.NET Core (.NET 6, 8, 10)

The redirect rule

This rewrite rule lowercases the scheme, host and path but leaves the query string alone, since tokens and other query values are often case-sensitive. It only redirects GET and HEAD requests, because redirecting a POST would lose the form data.

using System.Net;
using Microsoft.AspNetCore.Rewrite;
using Microsoft.Net.Http.Headers;

public sealed class RedirectLowerCaseRule : IRule
{
    public void ApplyRule(RewriteContext context)
    {
        HttpRequest request = context.HttpContext.Request;

        // Only redirect safe requests; a 301 on a POST would drop the form body.
        if (!HttpMethods.IsGet(request.Method) && !HttpMethods.IsHead(request.Method))
        {
            context.Result = RuleResult.ContinueRules;
            return;
        }

        string path = request.PathBase.Value + request.Path.Value;
        string host = request.Host.Value ?? string.Empty;

        if (path.Any(char.IsUpper) || host.Any(char.IsUpper))
        {
            // Lowercase scheme, host and path. Leave the query string exactly as it was.
            string location = $"{request.Scheme}://{host}{path}".ToLowerInvariant() + request.QueryString;

            HttpResponse response = context.HttpContext.Response;
            response.StatusCode = (int)HttpStatusCode.MovedPermanently;
            response.Headers[HeaderNames.Location] = location;
            context.Result = RuleResult.EndResponse;
            return;
        }

        context.Result = RuleResult.ContinueRules;
    }
}

Program.cs

// Program.cs
using Microsoft.AspNetCore.Rewrite;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();

// 1) Make every URL that ASP.NET Core *generates* lowercase
//    (Url.Action, asp-action/asp-controller tag helpers, RedirectToAction, LinkGenerator...).
builder.Services.Configure<RouteOptions>(options =>
{
    options.LowercaseUrls = true;
    options.LowercaseQueryStrings = false; // leave ?Token=AbC alone (often case-sensitive)
});

var app = builder.Build();

// 2) 301-redirect any *incoming* URL that contains uppercase letters.
//    Put this early, before static files and routing.
app.UseRewriter(new RewriteOptions().Add(new RedirectLowerCaseRule()));

app.UseStaticFiles();
app.UseRouting();
app.MapDefaultControllerRoute();
app.MapGet("/about-us", () => "About");

app.Run();

With both pieces in place, a request for /About-Us?Token=AbC returns 301 to /about-us?Token=AbC, and every link generated by tag helpers (asp-controller, asp-action, asp-page), Url.Action, RedirectToAction and LinkGenerator is already lowercase, so visitors rarely hit the redirect at all.

ASP.NET (.NET Framework) and Any IIS Site

On IIS you can do the redirect without code using the URL Rewrite module. This also works in front of ASP.NET Core apps hosted on IIS, if you prefer configuration over code:

<!-- web.config (requires the IIS URL Rewrite module) -->
<configuration>
  <system.webServer>
    <rewrite>
      <rules>
        <rule name="Lowercase URLs" stopProcessing="true">
          <match url="[A-Z]" ignoreCase="false" />
          <conditions>
            <!-- Only redirect GET/HEAD so form posts aren't broken -->
            <add input="{REQUEST_METHOD}" pattern="^(GET|HEAD)$" />
          </conditions>
          <!-- {URL} is the path only; the query string is appended unchanged -->
          <action type="Redirect" url="{ToLower:{URL}}" redirectType="Permanent" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

In classic ASP.NET MVC 5, you can also set routes.LowercaseUrls = true; in RouteConfig so Html.ActionLink and Url.Action produce lowercase links.

Things To Check

  • Hard-coded links and JavaScript: LowercaseUrls only affects URLs generated by routing. Links typed into views, fetch/AJAX calls and URLs in JavaScript need to be lowercase too, or they will go through a redirect (and POSTs won't be redirected at all).
  • Static files: on Linux, file names are case-sensitive. If you have /images/Logo.png on disk, the redirect to /images/logo.png will 404. Rename files to lowercase, or place the rewriter after UseStaticFiles() if you can't.
  • Canonical tags: output a lowercase <link rel="canonical"> on every page as a second signal to search engines.
  • Query strings: they are left as-is on purpose. If you also want them lowercase, set LowercaseQueryStrings = true and lowercase request.QueryString in the rule.

Why Lowercase URLs Matter for SEO

Search engines treat URLs as case-sensitive, so /Blog/My-Post and /blog/my-post are two different URLs with the same content. That splits links and ranking signals between duplicates. People also link to you with whatever casing they type; a 301 to one canonical lowercase URL consolidates all of those links.

Consistent casing also makes analytics cleaner: tools such as Google Analytics report each casing as a separate page unless every URL is normalized.

Frequently Asked Questions

Is ASP.NET Core routing case-sensitive?

No. Route matching in ASP.NET Core is case-insensitive by default, for both conventional and attribute routes. That is why uppercase and lowercase versions of a URL both work, and why you should redirect to one version.

What does LowercaseUrls do?

RouteOptions.LowercaseUrls makes the URLs that ASP.NET Core generates lowercase. It doesn't redirect incoming requests; you need a rewrite rule or middleware for that.

Is RedirectToAction case-sensitive?

No. RedirectToAction("Index", "Home") matches routes case-insensitively, and with LowercaseUrls = true the resulting Location header is lowercase.

Should the redirect be 301 or 302?

Use 301 (permanent). It tells search engines the lowercase URL is the real one and passes ranking signals to it.

Related: redirecting www and non-HTTPS traffic in ASP.NET Core.


Comments

No Comments

CAPTCHA

Tagged: ASP.NET, SEO


Join my email list!



ryan
About Me

With over 15 years in tech, I've excelled as a senior software engineer, specializing in ASP.NET, C#, SQL, Azure, and front-end technologies. I've led diverse projects across various sectors, from startups to global corporations, particularly during my decade in the San Francisco Bay Area.


Sign Up Hostinger Email