Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

System.Net.Uri with urlencoded characters

Tags:

c#

.net

I need to request the following URL inside my application:

http://feedbooks.com/type/Crime%2FMystery/books/top

When I run the following code:

Uri myUri = new Uri("http://feedbooks.com/type/Crime%2FMystery/books/top");

The Uri constructor decodes the %2F into a literal /, and I get a 404 error because it has changed the URL to:

http://feedbooks.com/type/Crime/Mystery/books/top

The Uri class has a constructor that takes a parameter dontEscape, but that constructor is deprecated and setting it to true has no effect.

My first thought was to do something like:

Uri myUri = new Uri("http://feedbooks.com/type/Crime%252FMystery/books/top");

With the hopes that it would convert %25 into a literal %, but that didn't work either.

Any ideas how to create a correct Uri object for this particular URL in .NET?

like image 412
Matt Bridges Avatar asked Feb 23 '10 18:02

Matt Bridges


Video Answer


2 Answers

It's a bit easier in .NET 4.0. You can put a setting in your config file like this:

<uri> 
<schemeSettings>
    <add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes" />
</schemeSettings>
</uri>

It only works for the 'http' and 'https' schemes.

Or here's a new version of the LeaveDotsAndSlashesEscaped method. It doesn't need a particular Uri instance, just call it when your application starts up:

private void LeaveDotsAndSlashesEscaped()
{
    var getSyntaxMethod = 
        typeof (UriParser).GetMethod("GetSyntax", BindingFlags.Static | BindingFlags.NonPublic);
    if (getSyntaxMethod == null)
    {
        throw new MissingMethodException("UriParser", "GetSyntax");
    }

    var uriParser = getSyntaxMethod.Invoke(null, new object[] { "http" });

    var setUpdatableFlagsMethod = 
        uriParser.GetType().GetMethod("SetUpdatableFlags", BindingFlags.Instance | BindingFlags.NonPublic);
    if (setUpdatableFlagsMethod == null)
    {
        throw new MissingMethodException("UriParser", "SetUpdatableFlags");
    }

    setUpdatableFlagsMethod.Invoke(uriParser, new object[] {0});
}
like image 144
Mike Hadlow Avatar answered Oct 16 '22 16:10

Mike Hadlow


I ran into the same problem using 2.0...

I discovered a workaround posted at this blog:

// System.UriSyntaxFlags is internal, so let's duplicate the flag privately
private const int UnEscapeDotsAndSlashes = 0x2000000;

public static void LeaveDotsAndSlashesEscaped(Uri uri)
{
    if (uri == null)
    {
        throw new ArgumentNullException("uri");
    }

    FieldInfo fieldInfo = uri.GetType().GetField("m_Syntax", BindingFlags.Instance | BindingFlags.NonPublic);
    if (fieldInfo == null)
    {
        throw new MissingFieldException("'m_Syntax' field not found");
    }
    object uriParser = fieldInfo.GetValue(uri);

    fieldInfo = typeof(UriParser).GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
    if (fieldInfo == null)
    {
        throw new MissingFieldException("'m_Flags' field not found");
    }
    object uriSyntaxFlags = fieldInfo.GetValue(uriParser);

    // Clear the flag that we don't want
    uriSyntaxFlags = (int)uriSyntaxFlags & ~UnEscapeDotsAndSlashes;

    fieldInfo.SetValue(uriParser, uriSyntaxFlags);
}

It works perfectly.

Hope this helps (better late than never!)

like image 29
Chase B. Gale Avatar answered Oct 16 '22 17:10

Chase B. Gale