SEO redirects in .NET + Optimizely
It's way more complicated to be unique nowadays. Having a website is one of the main ways to represent the company and basically, a must-have. But as important as to HAVE the website, it is also crucial to MAKE it easily searchable, especially in an environment of strong competition.
Apart from that, the website must also be highly positioned in the search results and to make it happen, it must meet many of the SEO conditions.
It usually ends with making the website follow one common pattern in the URLs, such as allowing only lowercase characters, ending (or not) with trailing slashes, or forcing the user to use www at the beginning of the URI. Thankfully, .NET comes with easy-to-use middleware to add rewrite rules, helping meet the SEO requirements.
All that needs to be done is to add URL Rewrite middleware in the Configure method of the Startup file.
app.UseRewriter(new RewriteOptions()
.SkipStaticFiles()
.SkipCmsUrls()
.AddRedirectToTrailingSlashesPermanent()
.AddRedirectToLowercaseUrlPermanent()
.SkipRemainingRulesIfDxp()
.AddRedirectToWwwPermanent());
Worth mentioning is that the order matters and the first one executed will be the top one, so it might be good to put the most frequently used rule there.
The rules in the example above use extension methods so the Startup file is clean and easy to read. The actual logic can be seen in the implementation of the methods. The first rule skips the static files, so the middleware doesn't apply the next rules when it discovers any file extension.
public static RewriteOptions SkipStaticFiles(this RewriteOptions options)
{
options.Add(context =>
{
bool hasFileExtension = Regex.IsMatch(context.HttpContext.Request.Path.Value, @".*/[^.]*\.[\d\w]+$");
if (hasFileExtension)
{
context.Result = RuleResult.SkipRemainingRules;
}
});
return options;
}
The next one is related to the CMS environment where we don't want to force any redirects which probably will result in breaking the platform. It adds URLs patterns that should not be redirected by the next rules. We can see URLs like util or episerver known from Optimizely CMS. It is also important to add URLs of any of the external tools installed in the CMS, like Localization DB provider or GETA Sitemaps. They can malfunction without those rules.
public static RewriteOptions SkipCmsUrls(this RewriteOptions options)
{
options.Add(context =>
{
if (context.HttpContext.Request.Path.StartsWithSegments("/util") ||
context.HttpContext.Request.Path.StartsWithSegments("/episerver") ||
context.HttpContext.Request.Path.StartsWithSegments("/modules") ||
context.HttpContext.Request.Path.StartsWithSegments("/localization-admin") ||
context.HttpContext.Request.Path.StartsWithSegments("/getaoptimizelysitemaps"))
{
context.Result = RuleResult.SkipRemainingRules;
}
});
return options;
}
Next, we have the trailing slashes rule which is just a simple regex redirection
public static RewriteOptions AddRedirectToTrailingSlashesPermanent(this RewriteOptions options)
{
options.AddRedirect("(.*[^/])$", "$1/", (int)HttpStatusCode.MovedPermanently);
return options;
}
The AddRedirectToLowercaseUrlPermanent is a bit more complicated as it requires the creation of a custom implementation of the Microsoft.AspNetCore.Rewrite.IRule interface, which exposes a method called ApplyRule
public void ApplyRule(RewriteContext context)
{
var request = context.HttpContext.Request;
var path = context.HttpContext.Request.Path;
var host = context.HttpContext.Request.Host;
if (path.HasValue && path.Value.Any(char.IsUpper) || host.HasValue && host.Value.Any(char.IsUpper))
{
var 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;
}
}
The last rule is built in .NET and adds a permanent redirect to www. When doing this in the Optimizely environment called DXP it is important to remember that this redirection can break access by using the default DXP URLs. This is the main reason why before the www redirection rule there was a rule checking if there is a URL other than the DXP one. The rule is another implementation of the IRule which looks like this:
public void ApplyRule(RewriteContext context)
{
var host = context.HttpContext.Request.Host;
if (host.HasValue && host.Value.EndsWith(".dxcloud.episerver.net"))
{
context.Result = RuleResult.SkipRemainingRules;
}
else
{
context.Result = RuleResult.ContinueRules;
}
}
That would be all. Now, our website can get a few more points in the global SEO race.
More articles
Optimizely SaaS CMS + Coveo Search Page
Short on time but need a listing feature with filters, pagination, and sorting? Create a fully functional Coveo-powered search page driven by data from the Optimizely SaaS CMS - all during just a break between coffee refills.
Block type selection doesn't work
Imagine you're trying to create a new block in a specific content area. You click the "Create" link, expecting to see a CMS modal with a list of available blocks. Instead, you're greeted with an empty view and a console error. What's going on?
Custom payment in Optimizely Commerce 14
The Commerce platform offers a few of the most common payment methods. However, they are not always enough, and it is absolutely natural to need a fully customized approach.
Optimizely Autocomplete (Statistics)
A user starts typing in the search input, and it returns suggestions for phrases they might be searching for. How to achieve this?
Global Components Builders
Implementing global common components every site consists of