Minesh Shah (Netcel)
+7
Feb 28, 2023
visibility 6153
star star star star star
(5 votes)

URL Rewrites in CMS12 (.Net 6)

URL rewriting is a common technique used in web applications to create user-friendly URLs that are easier to understand, provide consistency and have SEO benefits. In the past, URL rewriting was commonly accomplished using IIS URL Rewrite module. However, with the release of .NET Core, the process of rewriting URLs has undergone some changes.

Microsoft has introduced a new URL rewriting middleware called Microsoft.AspNetCore.Rewrite. This middleware is part of the ASP.NET Core framework and is designed to rewrite URLs in a much more flexible and efficient way.

One of the key benefits of using the Microsoft.AspNetCore.Rewrite middleware is that it allows URL rewriting without requiring IIS or any other web server. This means that we can create Optimizely Solutions that are completely self-contained and can be run on any platform.

Here is an example of how to use the Microsoft.AspNetCore.Rewrite middleware in .NET 6 to handle some common conventions like redirecting to https, enforcing lowercase urls and adding trailing slash to the end of all URLs:

Lower Case URL – Implement IRule Base Rule

    public class LowercaseUrlsRule : IRule
    {
        public int StatusCode { get; } = (int)HttpStatusCode.MovedPermanently;

        public void ApplyRule(RewriteContext context)
        {
            HttpRequest request = context.HttpContext.Request;
            PathString path = context.HttpContext.Request.Path;
            HostString host = context.HttpContext.Request.Host;

            if (path.HasValue && path.Value.Any(char.IsUpper) || host.HasValue && host.Value.Any(char.IsUpper))
            {
                HttpResponse response = context.HttpContext.Response;
                response.StatusCode = StatusCode;
                response.Headers[HeaderNames.Location] = (request.Scheme + "://" + host.Value + request.PathBase.Value + request.Path.Value).ToLower() + request.QueryString;
                context.Result = RuleResult.EndResponse;
            }
            else
            {
                context.Result = RuleResult.ContinueRules;
            }
        }
    }

Use Rules in Middleware Startup.cs

In the example below we are using the RewriteOptions class to define paths that should be negated, and adding the rules for forcing HTTPS, Lowercase and Trailing Slashes. I have explicitly added below app.UseStaticFiles() so the rules do not get added to files like css, javascript or images.

        app.UseStaticFiles();

        var options = new RewriteOptions()
            .Add(context =>
                {
                    if (context.HttpContext.Request.Path.StartsWithSegments("/util") || 
                        context.HttpContext.Request.Path.StartsWithSegments("/episerver") || 
                        context.HttpContext.Request.Path.StartsWithSegments("/modules"))
                    {
                        context.Result = RuleResult.SkipRemainingRules;
                    }
                })
            // Redirect to HTTPS
            .AddRedirectToHttpsPermanent()
            // Enforce lower case. 
            .Add(new LowercaseUrlsRule())
            // Enforce trailing slash.
            .AddRedirect("(.*[^/])$", "$1/");



        app.UseRewriter(options);

These techniques are not Optimizely specific and can be applied to any .Net Solution, more info on IRule based rewrites can be found here

Feb 28, 2023

Comments

EVT
EVT Jul 25, 2023 10:37 AM

Row

response.Headers[HeaderNames.Location] = url.ToLowerInvariant() + request.QueryString;

fails if there is a non ascii character in the URL. Perhaps it should be changed to 

response.Headers[HeaderNames.Location] = UriHelper.Encode(new Uri((request.Scheme + "://" + host.Value + request.PathBase.Value + request.Path.Value).ToLower() + request.QueryString));

Tim Hilton
Tim Hilton Jan 12, 2024 05:19 PM

Thanks for a useful article Minesh.

Just a point to note, these redirects are processing sequentially causing a number of redirects if mutiple conditions are met. 

For example if the url has uppercase characters and a missing trailling slash the response is 301 lowercase > 302 trailling slash > 200 ok.

A minor update to the LowercaseUrlsRule, to resolve the other conditions at the same time helps this.

string slash = !path.Value.EndsWith("/") ? "/" : string.Empty;
string lowerPath = $"https://{host.Value}{request.PathBase.Value}{request.Path.Value}{slash}".ToLower();
...

error Please login to comment.
Latest blogs
Building a Blazor Server UI Inside the Optimizely CMS 13 Admin Shell

What I learned shipping a Blazor Server UI inside Optimizely CMS 13 — Razor components in a NuGet package, the Blazor hub next to MapContent(),...

Stanisław Szołkowski | Sep 17, 2026 |

Giving Optimizely 13 Content Types Meaningful Icons and Thumbnails

When working with an Optimizely CMS solution that has evolved over time, it is common to end up with many content types. As the number grows, the...

Pär Wissmark | Sep 16, 2026 |

force-dynamic vs connection() for Optimizely Graph

If you have built an Optimizely CMS SDK site, you already know getContentByPath on a catch-all. This post is about the part that file never says ou...

Chirag Khanna | Sep 16, 2026 |

I built a thing - nOSC & nOCP - an experiment?

I don't think I'm always that convensional . And that's where this starts... So firstly, I was lucky enough to see OCP UI extensions for Optimizey...

Matt Pallatt | Sep 15, 2026

A day in the life of an Optimizely OMVP: OptiA11y: accessibility help for Optimizely editors that refuses to lie to them

Most accessibility tooling in the CMS space has the same shape. A crawler walks your published site, renders each page, runs axe-core over the DOM,...

Graham Carr | Sep 15, 2026

OptiPowerTools.ScheduledJobsInsights: Execution History for Optimizely’s Native Scheduled Jobs

A drop-in base class and Blazor UI that records what Optimizely CMS 13 scheduled jobs actually did — logs, metrics, result summaries, and retention.

Stanisław Szołkowski | Sep 15, 2026 |