带有urlencoded字符的System.Net.Uri

时间:2010-02-23 18:02:53

标签: c# .net

我需要在我的应用程序中请求以下URL:

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

当我运行以下代码时:

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

Uri构造函数将%2F解码为文字/,我收到404错误,因为它已将网址更改为:

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

Uri类有一个带参数dontEscape的构造函数,但不推荐使用该构造函数并将其设置为true无效。

我的第一个想法是做类似的事情:

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

希望它会将%25转换为文字%,但这也不起作用。

如何在.NET中为此特定URL创建正确的Uri对象?

4 个答案:

答案 0 :(得分:7)

在.NET 4.0中它更容易一些。您可以在配置文件中设置如下设置:

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

它仅适用于'http'和'https'方案。

或者这是LeaveDotsAndSlashesEscaped方法的新版本。它不需要特定的Uri实例,只需在应用程序启动时调用它:

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});
}

答案 1 :(得分:6)

我使用2.0 ...

遇到了同样的问题

我在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);
}

效果很好。

希望这会有所帮助(迟到总比没有好!)

答案 2 :(得分:2)

这是bug我提出了一段时间。它应该在4.0中修复,但我没有屏住呼吸。显然它仍然是RC中的一个问题。

答案 3 :(得分:1)

通过结合前面的2个答案,您可以使用一种方法,只需在.net 4和.net 3.5上运行的每个进程调用一次。

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

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" });

    FieldInfo flagsFieldInfo = typeof(UriParser).GetField("m_Flags", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.Instance);

    if (flagsFieldInfo == null)
    {
        throw new MissingFieldException("UriParser", "m_Flags");
    }
    int flags = (int) flagsFieldInfo.GetValue(uriParser);
    // unset UnEscapeDotsAndSlashes flag and leave the others untouched
    flags = flags & ~UnEscapeDotsAndSlashes;
    flagsFieldInfo.SetValue(uriParser, flags);

}