Redirect Non WWW to WWW using Asp.Net Core Middleware
Asked Answered
B

10

19

On an ASP.Net Core application startup I have:

RewriteOptions rewriteOptions = new RewriteOptions(); 

rewriteOptions.AddRedirectToHttps();

applicationBuilder.UseRewriter(rewriteOptions);

When in Production I need to redirect all Non WWW to WWW Urls

For example:

domain.com/about > www.domain.com/about

How can I do this using Rewrite Middleware?

I think this can be done using AddRedirect and Regex:

Github - ASP.NET Core Redirect Docs

But not sure how to do it ...

Barbie answered 6/5, 2017 at 17:29 Comment(1)
Does AddApacheModRewrite work in this case?Banbury
C
18

A reusable alternative would be to create a custom rewrite rule and a corresponsing extension method to add the rule to the rewrite options. This would be very similar to how AddRedirectToHttps works.

Custom Rule:

public class RedirectToWwwRule : IRule
{
    public virtual void ApplyRule(RewriteContext context)
    {
        var req = context.HttpContext.Request;
        if (req.Host.Host.Equals("localhost", StringComparison.OrdinalIgnoreCase))
        {
            context.Result = RuleResult.ContinueRules;
            return;
        }

        if (req.Host.Value.StartsWith("www.", StringComparison.OrdinalIgnoreCase))
        {
            context.Result = RuleResult.ContinueRules;
            return;
        }

        var wwwHost = new HostString($"www.{req.Host.Value}");
        var newUrl = UriHelper.BuildAbsolute(req.Scheme, wwwHost, req.PathBase, req.Path, req.QueryString);
        var response = context.HttpContext.Response;
        response.StatusCode = 301;
        response.Headers[HeaderNames.Location] = newUrl;
        context.Result = RuleResult.EndResponse;
    }
}

Extension Method:

public static class RewriteOptionsExtensions
{
    public static RewriteOptions AddRedirectToWww(this RewriteOptions options)
    {
        options.Rules.Add(new RedirectToWwwRule());
        return options;
    }
}

Usage:

var options = new RewriteOptions();
options.AddRedirectToWww();
options.AddRedirectToHttps();
app.UseRewriter(options);

Future versions of the rewrite middleware will contain the rule and the corresponding extension method. See this pull request

Cracy answered 14/2, 2018 at 9:59 Comment(2)
Is it intended to redirect only from no-subdomain to www with the PR, in case you want your application to handle different subdomains? So e.g. mydomain.org goes to www.mydomain.org, but ww2.mydomain.org remains unchanged?Supination
Adding if (req.Host.Value.EndsWith(".azurewebsites.net", StringComparison.OrdinalIgnoreCase)) { context.Result = RuleResult.ContinueRules; return; } is a useful addition.Ranunculaceous
R
11

Since ASP.NET Core 3.0 (2019) these methods can be used:

  • AddRedirectToWwwPermanent()
  • AddRedirectToWww()

Example

app.UseRewriter(new RewriteOptions()
  .AddRedirectToWww());

See https://learn.microsoft.com/en-us/aspnet/core/fundamentals/url-rewriting?view=aspnetcore-5.0

Robillard answered 13/9, 2021 at 12:48 Comment(2)
app.UseRewriter(new RewriteOptions().AddRedirectToWwwPermanent()); for permanent redirect use this.Thegn
The drawback from this method is that you cannot customize for things like not redirecting to Www when the domain is not the production domain (for example, not redirecting when viewing from azurewebsites.net).Ranunculaceous
B
5

I'm more of an Apache user and fortunately URL Rewriting Middleware in ASP.NET Core provides a method called AddApacheModRewrite to perform mod_rewrite rules on the fly.

1- Create a .txt file whatever the name and put these two lines into it:

RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]

2- then call it this way:

AddApacheModRewrite(env.ContentRootFileProvider, "Rules.txt")

Done!

Banbury answered 7/2, 2018 at 22:27 Comment(0)
H
3

Using just a regex,

Find ^(https?://)?((?!www\.)(?:(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]+-?)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))

Replace $1www.$2

Expanded

 ^                             # BOS
 (                             # (1 start), optional http(s)
      https?  ://
 )?                            # (1 end)
 (                             # (2 start), domains without www prefix
      (?! www\. )
      (?:
           (?: [a-z\u00a1-\uffff0-9]+ -? )*
           [a-z\u00a1-\uffff0-9]+ 
      )
      (?:
           \.
           (?: [a-z\u00a1-\uffff0-9]+ -? )*
           [a-z\u00a1-\uffff0-9]+ 
      )*
      (?:
           \.
           (?: [a-z\u00a1-\uffff]{2,} )
      )
 )                             # (2 end)
Hickey answered 7/2, 2018 at 22:49 Comment(1)
This regex solution seems good but doesn't have anything to do with ASP Rewrite Middleware and OP had similar regex-based solutions before bounty.Banbury
T
2

It's unclear from if what AddRedirect method does and if it actually accepts regex.

But to insert a "www" to a url without "www"?
You could try it with these strings:

string pattern = @"^(https?://)(?!www[.])(.*)$";
string replacement = "$1www.$2";

//Regex rgx = new Regex(pattern);
//string redirectUrl = rgx.Replace(url, replacement);

Because of the negative lookahead (?!www[.]) after the protocol, it'll ignore strings like http://www.what.ever

$1 and $2 are the first and second capture groups.

Trawick answered 6/5, 2017 at 18:45 Comment(2)
Seems ok, but why bother matching the whole URL if you can just match and replace the starting chars? string pattern = @"^https?://(?!www[.])"; with string replacement = "$&www.";Gyro
@JohanWentholt Well, I guess I wasn't sure back then if the regex engine would use $& or $0 for the match. But your version is the better golf. I'm kinda surprized to see that the guy put a big bounty on such an old question now. Oh never mind, he changed the question. Maybe he should have just started a new one...Trawick
S
1

I think instead of using Regex unless it is a must you can use the Uri class to reconstruct your url

var uri = new Uri("http://example.com/test/page.html?query=new&sortOrder=ASC");
var returnUri = $"{uri.Scheme}://www.{uri.Authority}
{string.Join(string.Empty, uri.Segments)}{uri.Query}";

And the result will look like

Output: http://www.example.com/test/page.html?query=new&sortOrder=ASC
Skylar answered 6/5, 2017 at 19:30 Comment(1)
I need to use Regex as this is used in ASP.NET Core method.Barbie
E
0

You don't need a RegEx, just a simple replace will work:

var temp = new string[] {"http://google.com", "http://www.google.com", "http://gmail.com", "https://www.gmail.com", "https://example.com"};

var urlWithoutWWW = temp.Where(d => 
                         d.IndexOf("http://www") == -1 && d.IndexOf("https://www") == -1);

foreach (var newurl in urlWithoutWWW)
{
     Console.WriteLine(newurl.Replace("://", "://www."));
}
Eyas answered 6/5, 2017 at 17:37 Comment(2)
I need to use Regex as this is used in ASP.NET Core method.Barbie
So, this can be used in .net core.Eyas
F
0

Here's a regex to try:

(http)(s)?(:\/\/)[^www.][A-z0-9]+(.com|.gov|.org)

It will select URLs like:

  • http://example.com
  • https://example.com
  • http://example.gov
  • https://example.gov
  • http://example.org
  • https://example.org

But not like:

  • http://www.example.com
  • https://www.example.com

I prefer to use explicit extensions (e.g. .com, .gov, or .org) when possible, but you could also use something like this if it is beneficial to your use case:

(http)(s)?(:\/\/)[^www.][A-z0-9]+(.*){3}

I would then approach the replacement with something like the following:

Regex r = new Regex(@"(http)(s)?(:\/\/)[^www.][A-z0-9]+(.*){3}");
string test = @"http://example.org";
if (r.IsMatch(test))
{
    Console.WriteLine(test.Replace("https://", "https://www."));
    Console.WriteLine(test.Replace("http://", "http://www."));
}
Forsake answered 6/5, 2017 at 17:53 Comment(1)
The regex does not seem correct [^www.] matches a single character that is not a w or . (dot). Try your regex with http://willywonka.com.Gyro
P
0

Most often these days you want both redirection to www AND https. hankors answer is great but entails two redirections instead of one so I have rewritten his custom rule to both add www and https when needed. The result is just one redirection (if you turn of https redirection in Azure).

    public class RedirectToHttpsWwwRule : IRule
{
    public void ApplyRule(RewriteContext context)
    {
        var req = context.HttpContext.Request;
        if (req.Host.Host.Equals("localhost", StringComparison.OrdinalIgnoreCase))
        {
            context.Result = RuleResult.ContinueRules;
            return;
        }
        HostString wwwHost;

        if (req.IsHttps)
        {
            if (req.Host.Value.StartsWith("www.", StringComparison.OrdinalIgnoreCase))
            {
                context.Result = RuleResult.ContinueRules;
                return;
            }
            else
            {
                wwwHost = new HostString($"www.{req.Host.Value}");
            }
        }
        else
        {
            if (req.Host.Value.StartsWith("www.", StringComparison.OrdinalIgnoreCase))
            {
                wwwHost = new HostString(req.Host.Value);
            }
            else
            {
                wwwHost = new HostString($"www.{req.Host.Value}");
            }
        }

        string newUrl = UriHelper.BuildAbsolute("https", wwwHost, req.PathBase, req.Path, req.QueryString);
        var response = context.HttpContext.Response;
        response.StatusCode = 301;
        response.Headers[HeaderNames.Location] = newUrl;
        context.Result = RuleResult.EndResponse;
    }
}
Protuberance answered 25/4, 2021 at 13:14 Comment(0)
R
0

I have used the answer of SuperDuck also in a .net 6 ASP.net application. My code is:

using Microsoft.AspNetCore.Rewrite;

app.UseRewriter(new RewriteOptions().AddRedirectToWwwPermanent().AddRedirectToHttpsPermanent()); // in program.cs

It redirects to the www subdomain and also to the https-version of the web-app.

Riki answered 19/11, 2021 at 15:24 Comment(1)
This does not really answer the question. If you have a different question, you can ask it by clicking Ask Question. To get notified when this question gets new answers, you can follow this question. Once you have enough reputation, you can also add a bounty to draw more attention to this question. - From ReviewFebri

© 2022 - 2024 — McMap. All rights reserved.