Aspnet Core Url Rewrite and Redirect with Umbraco/Cms and Database Sourced Rules
Storing ASPNET Core Url Rewrite/Redirect rules in a database

Search for a command to run...
Storing ASPNET Core Url Rewrite/Redirect rules in a database

No comments yet. Be the first to comment.
I am fortunate to have been able to chat with many people trying to get into software development/tech roles. My mission is to try my best to answer questions and provide my perspective with the hope that each person receives something positive out ...

Before COVID restrictions come to an end I wanted to get my Covid experience documented since it dominated a large part of the middle 2021 for us. For people that know me, this won't be new but I had the desire to get it on "paper", a cathartic livi...

Before COVID restrictions come to an end I wanted to get my Covid experience documented since it dominated a large part of the middle 2021 for us. And to put this into perspective as a freelancer, I also was out of work for a large portion of this t...

I started consulting with a company and told the CTO that I would help him fill the gaps because the team was becoming overextended in several different areas from Dev Ops, Azure, Infrastructure, Internal Projects and Development (adding features/etc...

We recently had a strange scenario where I needed to confirm a customer's shopify log in credentials in order to "transfer" their account to an internal system in the most seamless way possible. Not to get into too many implementation details but th...

I recently migrated an older Umbraco CMS website to version 9 which is a much cleaner architecture that runs on top of aspnet core. One of the items that I left for the end was the URL rewriting piece which mostly existed for some redirects from over 6 years ago so I didn't prioritize it for the launch. The old Umbraco site had these url rewrite/redirect rules in the webconfig and the new aspnet core middleware can read them from a file however let's be honest, we don't want to manage these in a file we have to check-in and out of source control. Let's keep it simple and do the following:
Of course, we could overcomplicate the hell out of this and add rules to Umbraco and let the user configure them but not a customer requirement at this time therefore let's just get it done and working and iterate over it later if needed.
How do we do this? First, Umbraco ships with an ORM called NPoco so we can leverage that to access the database. Next, we create a table and class to read the information, and last we configure the middleware. The process is very straightforward and simple.
SQL Table:
-- Create table [dbo].[RewriteRules]
--
PRINT (N'Create table [dbo].[RewriteRules]')
GO
CREATE TABLE dbo.RewriteRules (
Id int IDENTITY,
Xml varchar(max) NULL,
CONSTRAINT PK_RewriteRules_Id PRIMARY KEY CLUSTERED (Id)
)
GO
C# Class for NPoco:
[PrimaryKey("Id")]
public class RewriteRules
{
public int Id { get; set; }
public string Xml { get; set; }
}
Now for the fun part, we just read from the table in the Startup:
RewriteRules rewrites = null;
try {
using(var db = new Database(_config.GetConnectionString("umbracoDbDSN")) {
rewrites = db.SingleById <RewriteRules>(1); // we only have one row
}
if (rewrites != null) {
using(var m = new StringReader(rewrites.Xml)) {
var options = new RewriteOptions().AddIISUrlRewrite(m);
if (!env.IsDevelopment()) {
options.AddRedirectToHttps();
}
app.UseRewriter(options);
}
}
} catch (Exception ex) {}
Quick tip. The middleware should probably be configured toward the top prior to the static files as you want this to always run. Also, not all rules are supported like the IsFile and IsDirectory contraints. The URL Rewriting Middleware is provided by the Microsoft.AspNetCore.Rewrite package, which is implicitly included in ASP.NET Core apps.
Here is an example of the ruleset:
<rewrite>
<rules>
<rule name="Testing" stopProcessing="true">
<match url="(.*)"/>
<conditions logicalGrouping="MatchAny" trackAllCaptures="false">
<add input="{HTTP_HOST}" pattern="^dev1"/>
<add input="{HTTP_HOST}" pattern="^local"/>
<add input="{HTTP_HOST}" pattern="staging"/>
</conditions>
<action type="None"/>
</rule>
<rule name="Prevent wp-login.php" stopProcessing="true">
<match url="wp-login.php"/>
<conditions logicalGrouping="MatchAll" trackAllCaptures="false"/>
<action type="AbortRequest"/>
</rule>
<rule name="Shop Redirect" stopProcessing="true">
<match url="(.*)"/>
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_HOST}" pattern="^shop.domain2.com"/>
</conditions>
<action type="Redirect" url="https://shop.domain.com"/>
</rule>
<rule name="redirect store" stopProcessing="true">
<match url="store/"/>
<conditions logicalGrouping="MatchAll" trackAllCaptures="false"/>
<action type="Redirect" url="https://shop.domain.com"/>
</rule>
<rule name="redirect menu" stopProcessing="true">
<match url="^menu.html"/>
<conditions logicalGrouping="MatchAll" trackAllCaptures="false"/>
<action type="Redirect" url="https://www.domain.com/menu"/>
</rule>
<rule name="domain.com base" stopProcessing="true">
<match url="(.*)"/>
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_HOST}" pattern="^domain\.com$" negate="true"/>
<add input="{R:0}" pattern="umbraco" negate="true"/>
</conditions>
<action type="Redirect" url="https://domain.com/{R:1}"/>
</rule>
<rule name="Force SSl" enabled="true" stopProcessing="true">
<match url="(.*)"/>
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTPS}" pattern="^OFF$"/>
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}"/>
</rule>
</rules>
</rewrite>
In future iterations of this we may want to create some IRule's that read and cache the database rules so that we can do this on the fly, or add them to Umbraco to manage in the backend. These rules change very infrequently so we also have to consider whether that work is necessary (hint, it is not).