URL Redirect & Rewrite Operations in .NET CORE
One of the cool things in .NET Core is flexibility to rewrite incoming URLs and change directions of resources to new URLs. You will be reading the way of implementing your own ReWrite Middleware, here. Let’s give it a shot with this article!
At first, I want to make clear Redirect and Rewrite operations. They both are similar but have differences in their executions.
Redirection causes a new request in the browser by sending 301 (Moved Permanently) and 302. And this operation tells the client to access to aimed page via another URL. The server will use the new URL to process the request. These explanation is also tell us what context.Response.Redirect()
function does. When this operation is executed, seeing the new URL on the browser and having results mean the operation had successfully completed.
Rewriting plays with current request’s path. When we configurate any rewrite middleware, server sees the new URL and runs with the new path. Unlike redirection, the rewrited URL does not seem on the browsers URL bar.
There are several reasons to apply these two operations to our request pipeline. Some of them are;
- To Create Short Versions of Long URLs
- To Make the URL Prettier
- To Cover Broken Links
In my case; I want to avoid/prevent extra slashes in my URL. At both steps below, we’ll apply the solution with redirection and rewriting methods. You may choose most useful ones for your project.
Firstly, o create this middleware you need to have the following namespace in your Startup.cs:
using Microsoft.AspNetCore.Rewrite;
1- Using the Rewrite/Redirect Middleware Inline in Startup.cs
In the Configure method which is used to change the HTTP request pipeline:
var rewriteOptions = new RewriteOptions()
.AddRewrite(@"account//+(.*)", "account/$1", true)
.AddRewrite(@"(\/+)account/(.*)", "account/$2",true)
.AddRewrite(@"(\/+)account(\/+)(.*)", "account/$3",true);app.UseRewriter(rewriteOptions);
The first parameter is the Regular Expression which is the pattern we want to see our URL to catch it up. The parentheses are individually called a capture group. Every capture group is pointing with a $ symbol.
Second parameter is the replacement of the new URL. I want to place my URL such as “account/{SomeWord}”. $1 represents the group right after “account/” part of my URL here → “account//+(.*)”
Third parameter is asking us for skipping remaining rules for this pattern and takes true/false.
If we need to redirect these URLs to the target URL, the solution is;
var redirectOptions = new RewriteOptions()
.AddRedirect(@"account//+(.*)", "account/$1", 301)
.AddRedirect(@"(\/+)account/(.*)", "account/$2", 301)
.AddRedirect(@"(\/+)account(\/+)(.*)", "account/$3", 301)
app.UseRewriter(redirectOptions);
At third parameter, we need to specify the status code for redirection. And you will see the request’s acts here.
2- Using the Rewrite/Redirect Middleware in External Path
The same operations but applying the solution is in external way. We are going to point an XML file to get the custom rules and replacement patterns. In Startup.cs:
using (var iisUrlRewriteReader = File.OpenText
(Path.Combine(Directory.GetCurrentDirectory(),"RewriteRules.xml")))
{
var options = new RewriteOptions()
.AddIISUrlRewrite(iisUrlRewriteReader); app.UseRewriter(options);
}
And in our RewriteRules.xml file we will have our rules in XML format. These rules redirects to the target urls. If you want it to work as rewriting process, you will need to change action types to “Rewrite”. Here is how I solved the three redirects I needed:
<?xml version="1.0" encoding="utf-8"?>
<rewrite>
<rules>
<rule name="Redirect account//+...">
<match url="^account/(/+)([_0-9a-z-]+)" />
<action type="Redirect" url="account/{R:2}" />
</rule>
<rule name="Redirect //+account/...">
<match url="^(/+)account/([_0-9a-z-]+)" />
<action type="Redirect" url="account/{R:2}" />
</rule>
<rule name="Redirect //+account//+...">
<match url="^(/+)account/(/+)([_0-9a-z-]+)" />
<action type="Redirect" url="account/{R:3}" />
</rule>
</rules>
</rewrite>
As you see, I have {R:2} symbol here unlike the inline method. We create a new pattern as account/{R:2}, we get the {R:2} part from our match rule.
Thank you for reading this article, I hope you enjoyed. Happy coding!