1

I have the below regex which I used to perform redirections

string requestedPath = HttpUtility.UrlDecode(this.StripLanguage(currentContext.InputUrl.AbsolutePath));
string requestedPathAndQuery = HttpUtility.UrlDecode(currentContext.InputUrl.PathAndQuery);
string requestedRawUrl = HttpUtility.UrlDecode(currentContext.InputUrl.PathAndQuery);
string requestedUrl =
    HttpUtility.UrlDecode(
        string.Concat(
            currentContext.InputUrl.Scheme,
            "://",
            currentContext.InputUrl.Host,
            requestedRawUrl));

string requestedRawUrlDomainAppended = HttpUtility.UrlDecode(currentContext.InputUrl.AbsoluteUri);
string requestedPathWithCulture = HttpUtility.UrlDecode(currentContext.InputUrl.AbsolutePath);

                    var finalRequestedURL = string.Empty;
finalRequestedURL = Regex.IsMatch(requestedPathAndQuery,matchPattern.Trim(),RegexOptions.IgnoreCase)
                    ? requestedPathAndQuery
                    : Regex.IsMatch(requestedPath,matchPattern.Trim(),RegexOptions.IgnoreCase)
                        ? requestedPath
                        : Regex.IsMatch(requestedPathWithCulture,matchPattern.Trim(),RegexOptions.IgnoreCase)
                            ? requestedPathWithCulture
                            : Regex.IsMatch(requestedRawUrl,matchPattern.Trim(),RegexOptions.IgnoreCase)
                                ? requestedRawUrl
                                : Regex.IsMatch(requestedUrl,matchPattern.Trim(),RegexOptions.IgnoreCase)
                                    ? requestedRawUrlDomainAppended
                                    : string.Empty;

The matchPattern variable is the Url. Example: (.*)/articles/my-article(.*) should redirect to http://www.google.com

The regex works fine but when it comes to lots of requests, our CPU goes to 100%.

Is there any solution to optimized the above?

Thanks

6
  • Use String.Contains("/articles/my-atricle") and skip the regex altogether. Commented Sep 13, 2018 at 17:59
  • How many matchPattern's are there? You can try to compile them and store in dictionary based on pattern. Also moving matchPattern.Trim() to separate variable will not solve the issue but still is nice. Commented Sep 13, 2018 at 18:01
  • @GuruStron what do you mean by compiling them? Sorry for noob question but i am not familiar with regex that much Commented Sep 13, 2018 at 18:04
  • @HishaamNamooya see this Commented Sep 13, 2018 at 18:06
  • @HishaamNamooya - I believe the idea was to use the RegexOptions.Compiled flag, but only do that if you are going to store that Regex and reuse it. Commented Sep 13, 2018 at 18:07

2 Answers 2

2

I would try creating an actual Regex variable and reuse it. That should help to speed things up. I would also maybe recommend changing that ternary business into just regular if/ else if / else statements. I think it would be more readable (just a personal opinion).

string requestedPath = HttpUtility.UrlDecode(this.StripLanguage(currentContext.InputUrl.AbsolutePath));
string requestedPathAndQuery = HttpUtility.UrlDecode(currentContext.InputUrl.PathAndQuery);
string requestedRawUrl = HttpUtility.UrlDecode(currentContext.InputUrl.PathAndQuery);
string requestedUrl =
    HttpUtility.UrlDecode(
        string.Concat(
            currentContext.InputUrl.Scheme,
            "://",
            currentContext.InputUrl.Host,
            requestedRawUrl));

string requestedRawUrlDomainAppended = HttpUtility.UrlDecode(currentContext.InputUrl.AbsoluteUri);
string requestedPathWithCulture = HttpUtility.UrlDecode(currentContext.InputUrl.AbsolutePath);

var regex = new Regex(matchPattern.Trim(), RegexOptions.IgnoreCase);
var finalRequestedURL = regex.IsMatch(requestedPathAndQuery)
                    ? requestedPathAndQuery
                    : regex.IsMatch(requestedPath)
                        ? requestedPath
                        : regex.IsMatch(requestedPathWithCulture)
                            ? requestedPathWithCulture
                            : regex.IsMatch(requestedRawUrl)
                                ? requestedRawUrl
                                : regex.IsMatch(requestedUrl)
                                    ? requestedRawUrlDomainAppended
                                    : string.Empty;

Edit

As I pointed out in my comment above, there are two string which are identical which would save you a comparison if you remove one of them.

string requestedPath = HttpUtility.UrlDecode(this.StripLanguage(currentContext.InputUrl.AbsolutePath));
string requestedPathAndQuery = HttpUtility.UrlDecode(currentContext.InputUrl.PathAndQuery);

// This string is identical to requestPathAndQuery, so I am removing it
// string requestedRawUrl = HttpUtility.UrlDecode(currentContext.InputUrl.PathAndQuery);

string requestedUrl =
    HttpUtility.UrlDecode(
        string.Concat(
            currentContext.InputUrl.Scheme,
            "://",
            currentContext.InputUrl.Host,
            requestedRawUrl));

string requestedRawUrlDomainAppended = HttpUtility.UrlDecode(currentContext.InputUrl.AbsoluteUri);
string requestedPathWithCulture = HttpUtility.UrlDecode(currentContext.InputUrl.AbsolutePath);

var regex = new Regex(matchPattern.Trim(), RegexOptions.IgnoreCase);
var finalRequestedURL = string.Empty;

// You could even add in brackets here to aid readability but this
// helps remove the indententation/nesting that makes the code harder
// to read and follow
if (regex.IsMatch(requestedPathAndQuery)) finalRequestURL = requestedPathAndQuery;
else if(regex.IsMatch(requestedPath)) finalRequestURL = requestedPath;
else if (regex.IsMatch(requestedPathWithCulture)) finalRequestURL = requestedPathWithCulture;
else if (regex.IsMatch(requestedUrl)) finalRequestURL = requestedRawUrlDomainAppended;
Sign up to request clarification or add additional context in comments.

5 Comments

So, the main changes is to initialize the Regex and then reuse it?
@HishaamNamooya - Yes, and as was pointed out in the other comments, you could go a step further and use the Compiled flag which would give you even better performance, BUT read the linked article which explains what that does. You absolutely would want to store that Regex object in your class somewhere or in a collection. DO NOT create a Regex with the Compiled option each time your function is called.
The expression will be different. I have around 18K of different pattern and each time there is an http request, it will call my Redirection method which contains the above code
@HishaamNamooya - Removed the note about reusing the expression then. Did you note my comment to the main question about the identical strings. It would save you a comparison if you removed one of them.
Applying the code you provided and removing the additional IsMatch seems to fix the issue. I’ll will be monitoring it just in case
0

As I stated in comments, if you anticipate only limited number of different patterns which can be reused through lifecycle of your app you can create a static Dictionary(I think better use concurrent one) and cache this regexps and reuse them.

EDIT

example code:

public class MyHandler
{
    private static ConcurrentDictionary<string, Regex> dict = new ConcurrentDictionary<string, Regex>();

    public void Handle(string urlPattern)
    {
        urlPattern = urlPattern.Trim();
        var regex = dict.GetOrAdd(urlPattern, s => new Regex(urlPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase));
        // use regex
    }
}

Also test if RegexOptions.Compiled option works for you, cause it actually can make things slower

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.