[ENH] Pattern matching for Url Mappings
Closed this issue · 6 comments
Oqtane Info
Version - 5.2.3
Render Mode - Static
Interactivity - Server
Database - SQL Server
Describe the enhancement
Migrating content from another CMS or active website to Oqtane requires creating hundreds or even thousands of Url Mappings, as Oqtane uses a delimiter character (!) in the path for parameters.
Therefore, even if a page is called the same, i.e. blogs, the page path in Oqtane would become blogs/!/{id}/{slug}
, so the original blogs/{id}/{slug}
will all result in broken links. Because of this, you can expect to receive thousands of broken links, one for each publicly available blog.
A possible work-around for this issue would be a sql (or C#) script that iterates over all the blogs and, for each, adds a url mapping to accomodate the new url template. However, this can become problematic when you have to perform this for tens of entities, ending up with, possibly, tens of thousands of entries in the UrlMapping table.
Oqtane should definitely support pattern matching to ease the migration process from other CMS or even regular Blazor applications, therefore attracting more users.
For example, a simple pattern matching could map blogs/*
to blogs/!/*
. This could later on perhaps be enhanced with additional features like mapping blogs/{id}/{slug}
to blogs/!/{slug}/{id}
, capturing and reordering path parameters.
Nonetheless, I consider that a basic pattern matching like the first one is vital for this framework.
@mdmontesinos this was considered when Url Mapping was introduced but the conclusion was that it would be better to delegate this responsibility to infrastructure components which are specialized for this purpose. For example, IIS already supports pattern-based rewriting in your web.config which is highly optimized based on decades of production usage. It is not very user friendly as there is no UI however one of the philosophies in Oqtane is to not re-invent the wheel.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath=".\AssemblyName.exe" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="InProcess" />
<rewrite>
<rules>
<rule name="redirect" enabled="true">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" negate="true" pattern="^NewDomain\.com$" />
</conditions>
<action type="Redirect" url="https://NewDomain.com/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
</location>
</configuration>
@sbwalker Perhaps complex url mappings do indeed need to be handled by the infrastructure, but I still believe Oqtane should provide, at least, a basic mechanism of wildcard url mapping.
There are cases where you don't have access to infrastructure configuration or when the provider does not allow doing this.
It is important to note that Url Mappings in Oqtane was NOT intended to be a general Url rewriter. It is currently only utilized in the scenario where the route path cannot be determined (ie. a 404). In this exception case it uses the Url Mappings to determine if the user should be redirected to a different route path. As a result of this behavior, this feature has very limited impact on performance as it is not being invoked for every request - it is only invoked for 404s. What you are suggesting is that Url Mappings should be a full featured Url rewriter which would be executed on every request (a much larger performance impact). This is the reason why I think the IIS Url rewriter is a better approach, as it has already been extensively optimized for performance.
I didn't actually mean to change the current behaviour. It should still only be applied when the request results in a 404, for obvious performance reasons. However, when trying to find a url mapping that applies to the missing route, it could do it with a direct mapping or with a wildcard.
As I mentioned, this was considered in the originally implementation but was not included due to the following....
let's say you have a Url of "blogs/my-old-cms-url"
and let's assume that this does not directly map to a route in Oqtane - which means it is a 404
Currently Oqtane can do a direct 1:1 lookup - it can look for "blogs/my-old-cms-url" and determine if there is a mapping, and if so do the redirect.
If Oqtane were to support wildcards, there is no longer a simple 1:1 mapping. There would need to be logic to load all of the wildcard mappings defined for the site, iterate through them to perform a RegExp on each to determine if there is a match, and if so then determine how to rewrite the url to handle the wildcard.
In your example, let's now assume that you have a link to a blog on the new site which has a broken link ie. "blogs/!/99/a-broken-link". It will match the wildcard "blogs/*" and substitute the prefix to create "blogs/!/!/99/a-broken-link" - which is still a 404... so will result in an infinite loop.
For the reason outlined above I believe it is best for Oqtane to retain a simple Url Mapping approach and require users to provide the explicit mappings rather than using wildcards. This could potentially be simplified by allowing users to do a bulk upload of mappings.
@sbwalker I understand your points, the infinite loop is definitely a considerable issue to consider. The bulk upload of mappings might be a nice "workaround" (although it's essentially the same as a sql script). In the mean time, I'll explore how to do url mappings in an Azure deployment (if anyone has any pointers, I'll appreciate them)