Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Odd string.Replace Chaining Behavior


:P
On this page:

I ran into a bit of a head scratcher today with a routine that does some string manipulation. It's an old routine that I use to help me do the equivalent of ResolveUrl() outside of the context of the ASP.NET Page framework - typically in static code somewhere or as part of a handler or other component.

The process is easy enough but I ran into a snag with the special case of resolving a root web path (ie. /wwbanner.ashx for example) and the routine has some admittedly hacky code that checks for the possibility of duplicated slashes in the front. So basically there's some code that looks like this:

newUrl = HttpContext.Current.Request.ApplicationPath +
      originalUrl.Substring(1).Replace("//","/");

Now that seems reasonable to me and I could swear that this code should work.

However it doesn't. If I pass in ~/wwbanner.ashx with a root web the URL gets generated as:

//wwbanner.ashx

which oddly enough goes out and downloads a whole HTML page from some PHP server off the Web (which is really quite a bizarre matter all on its own).

Honestly I can't figure out though why the above code DOESN'T work. The last Replace() at the end of the string expression should handle the double forward slashes. If I explicitly put the Replace() portion onto a separate line of code the code starts working properly:

newUrl = HttpContext.Current.Request.ApplicationPath +
       originalUrl.Substring(1);
newUrl = newUrl.Replace("//", "/");

this properly produces:

/wwbanner.ashx

which works as expected and properly fires my local banner manager in the site.

Anybody see which part of the forest I'm missing here and why the first fails and the latter works? It seems to me I SHOULD be able to chain string commands together and get expectable results - in fact I'm pretty sure I do this in other places and it works just fine. But somehow in this scenario it seems that .Replace() in particular is not behaving properly. <shrug>

Posted in .NET  CSharp  

The Voices of Reason


 

Dennis
March 05, 2008

# re: Odd string.Replace Chaining Behavior

Hi Rick,

everything works as expected:

In the first snippet, the Replace function is applied to the Substring(1) of the originalUrl, which means it is applied to "/wwbanner.ashx". Here it can't find any double slashes and does nothing. This results in "/" + "/wwbanner.ashx" = "//wwbanner.ashx".

In the second snippet, the two strings are FIRST put together, thus producing "//wwbanner.ashx" first. Replace applied on this string, is now able to do its work as it finds the double slash at the beginning. Thus it produces "/wwbanner.ashx".

Don't start downloading the .net symbols, everything's fine ;-)

HTH, Dennis

Alison
March 05, 2008

# re: Odd string.Replace Chaining Behavior

Isnt it because you need to bracket everything as such:

newUrl = (HttpContext.Current.Request.ApplicationPath +
originalUrl.Substring(1)).Replace("//","/");

Otherwise you are only doing the replace on the substring(1), which isnt going to match?

Dennis
March 05, 2008

# re: Odd string.Replace Chaining Behavior

@Alison: Yes this is exactly what I've said :-)

Alison
March 05, 2008

# re: Odd string.Replace Chaining Behavior

@Dennis: Yes, sorry, think we posted at the same time!

Dennis
March 05, 2008

# re: Odd string.Replace Chaining Behavior

@Alison: No problem :-) How do they say - Make assurance double sure!
A nice day to you all from Germany!

Richard Deeming
March 05, 2008

# re: Odd string.Replace Chaining Behavior

Assuming you have a reference to the System.Web assembly, why not use the methods from the VirtualPathUtility class:

http://msdn2.microsoft.com/en-us/library/system.web.virtualpathutility.aspx

newUrl = VirtualPathUtility.ToAbsolute(originalUrl);

Eber Irigoyen
March 05, 2008

# re: Odd string.Replace Chaining Behavior

actually I think it needs to be

newUrl = (HttpContext.Current.Request.ApplicationPath +
originalUrl).Substring(1).Replace("//","/");

the other slash is coming from the applicationPath

Eber Irigoyen
March 05, 2008

# re: Odd string.Replace Chaining Behavior

never mind, it should be

newUrl = (HttpContext.Current.Request.ApplicationPath +
originalUrl.Substring(1)).Replace("//","/");

but you are not actually using HttpContext.Current.Request.ApplicationPath, are you?

Rick Strahl
March 05, 2008

# re: Odd string.Replace Chaining Behavior

@Richard - Because virtual path provider is not reliable in various situations - it doesn't behave the same way as ResolveUrl with various combinations of full Urls. I had a post on this subject a long time back:

http://www.west-wind.com/WebLog/posts/154812.aspx

which (if you look through the comments) goes through a whole bunch of the issues. The end result was the above function (or part of it anyway).

Rick Strahl
March 05, 2008

# re: Odd string.Replace Chaining Behavior

@Dennis - Duh - of course <g>. Ah yes - the forest for the trees at times!!!

Dennis
March 05, 2008

# re: Odd string.Replace Chaining Behavior

@Rick: Yeah, that's true! Two minutes later, and I'd have downloaded the symbols <g>!!!

Bill Williamson
March 06, 2008

# re: Odd string.Replace Chaining Behavior

"which oddly enough goes out and downloads a whole HTML page from some PHP server off the Web (which is really quite a bizarre matter all on its own)."

Are you using openDNS? If so, it will auto-redirect your DNS query to a likely match, and your program will be none the wiser.

Rick Strahl
March 06, 2008

# re: Odd string.Replace Chaining Behavior

Bill - no, i'm running a straight net connnection here, which is why that seems very odd. When I explicitly type this into the address bar I end up with RoadRunner page, so I suspect that's what's going. RoadRunner's proxy is picking this up and redirecting somewhere... didn't notice that originally as I was just skimming the HTML dumped into the page where the banner code should have gone.

john
March 22, 2008

# re: Odd string.Replace Chaining Behavior

Rick, if I am not mistaken, depending on how you have your webserver set up, Request.ApplicationPath may return two different results. It may or may not return the application name.

When moving code like this that worked fine on localhost to another hosting environment, for example, Request.ApplicationPath may or may not return a trailing forward slash.

So if Requestion.Application Path returns /YourWebSite, concatenating the strings will work fine. But if it returns "/", you will concat this to the string replace function that has been computed to begin with a forward slash.

Here is what I do: Some new things here:

public static string ResolveUrl(string originalUrl)
        {
            if (String.IsNullOrEmpty(originalUrl))
                return String.Empty;

            if (Regex.IsMatch(originalUrl, "http(s?):|www."))
                return originalUrl;

            if (Regex.IsMatch(originalUrl, "~/[^/]"))
            {
                string newUrl = "";

                if (HttpContext.Current != null)
                {
                    newUrl = String.Concat(MyApplicationPath, originalUrl.Replace("~/", ""));
                }
                else
                    throw new ArgumentException("Invalid URL: Relative URL not allowed.");
                return newUrl;

            }
            return originalUrl;
        }

        private static string m_appPath = String.Empty;
        public static string MyApplicationPath
        {
            get
            {
                if (String.IsNullOrEmpty(m_appPath))
                {
                    m_appPath = HttpContext.Current.Request.ApplicationPath;
                    m_appPath = m_appPath.EndsWith("/") ? m_appPath : String.Concat(m_appPath, "/");
                }
                return m_appPath;
            }
        }

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024