如何让Uri.EscapeDataString符合RFC 3986

And*_*ott 30 .net openid uri escaping oauth

Uri类默认为RFC 2396.对于OpenID和OAuth,我需要符合RFC 3986的Uri转义.

System.Uri类文档:

默认情况下,URI中的任何保留字符都按照RFC 2396进行转义.如果启用了国际资源标识符或国际域名解析,则此行为会发生变化,在这种情况下,URI中的保留字符将根据RFC 3986和RFC 3987进行转义.

该文档还指出激活此IRI模式以及RFC 3986行为意味着将一个uri节元素添加到machine.config并将其添加到app/web.config文件中:

<configuration>
  <uri>
  <idn enabled="All" />
  <iriParsing enabled="true" />
  </uri>
</configuration>
Run Code Online (Sandbox Code Playgroud)

但是,无论是否存在于.config文件中,我都会获得与.NET 3.5 SP1应用程序相同的(非3986)转义行为. 我还需要做些什么Uri.EscapeDataString才能使用RFC 3986规则?(具体来说,要转义RFC中定义的保留字符)

And*_*ott 35

由于无法让Uri.EscapeDataString采用RFC 3986行为,我编写了自己的RFC 3986兼容转义方法.它利用Uri.EscapeDataString,然后"升级"转义为RFC 3986合规性.

/// <summary>
/// The set of characters that are unreserved in RFC 2396 but are NOT unreserved in RFC 3986.
/// </summary>
private static readonly string[] UriRfc3986CharsToEscape = new[] { "!", "*", "'", "(", ")" };

/// <summary>
/// Escapes a string according to the URI data string rules given in RFC 3986.
/// </summary>
/// <param name="value">The value to escape.</param>
/// <returns>The escaped value.</returns>
/// <remarks>
/// The <see cref="Uri.EscapeDataString"/> method is <i>supposed</i> to take on
/// RFC 3986 behavior if certain elements are present in a .config file.  Even if this
/// actually worked (which in my experiments it <i>doesn't</i>), we can't rely on every
/// host actually having this configuration element present.
/// </remarks>
internal static string EscapeUriDataStringRfc3986(string value) {
    // Start with RFC 2396 escaping by calling the .NET method to do the work.
    // This MAY sometimes exhibit RFC 3986 behavior (according to the documentation).
    // If it does, the escaping we do that follows it will be a no-op since the
    // characters we search for to replace can't possibly exist in the string.
    StringBuilder escaped = new StringBuilder(Uri.EscapeDataString(value));

    // Upgrade the escaping to RFC 3986, if necessary.
    for (int i = 0; i < UriRfc3986CharsToEscape.Length; i++) {
        escaped.Replace(UriRfc3986CharsToEscape[i], Uri.HexEscape(UriRfc3986CharsToEscape[i][0]));
    }

    // Return the fully-RFC3986-escaped string.
    return escaped.ToString();
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你的角色列表.我自己做了一个这样的衬里:Regex.Replace(Uri.EscapeDataString(s),"[\!\*\'\\(\\)]",函数(m)Uri.HexEscape(Convert.ToChar) (m.Value(0)的ToString()))) (4认同)
  • 你知道.net 4.5是否真的最终解决了这个问题?http://msdn.microsoft.com/en-us/library/hh367887(v=VS.110).aspx (2认同)
  • 我不相信. (2认同)
  • .NET 4.5修复了这个问题. (2认同)