31

UriクラスのデフォルトはRFC2396です。OpenIDとOAuthの場合、RFC3986に準拠したUriエスケープが必要です。

System.Uriクラスのドキュメントから:

デフォルトでは、URIの予約文字はRFC 2396に従ってエスケープされます。この動作は、InternationalResourceIdentifiersまたはInternationalDomainNameの解析が有効になっている場合に変更されます。この場合、URIの予約文字はRFC3986およびRFC3987に従ってエスケープされます。

ドキュメントには、このIRIモードをアクティブ化すると、RFC 3986の動作は、uriセクション要素をmachine.configに追加し、これをapp/web.configファイルに追加することを意味するとも記載されています。

<configuration>
  <uri>
  <idn enabled="All" />
  <iriParsing enabled="true" />
  </uri>
</configuration>

しかし、これが.configファイルに存在するかどうかに関係なく、.NET 3.5 SP1アプリで同じ(3986以外の)エスケープ動作が発生します。 RFC 3986ルールを使用するには、他に何をする必要がありますか?Uri.EscapeDataString(具体的には、そのRFCで定義されている予約文字をエスケープするため)

4

5 に答える 5

38

Uri.EscapeDataStringにRFC3986の動作をさせることができなかったので、私は独自のRFC3986準拠のエスケープメソッドを作成しました。Uri.EscapeDataStringを利用してから、エスケープをRFC3986準拠に「アップグレード」します。

/// <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();
}
于 2009-05-12T15:45:50.750 に答える
4

これは実際には.NET4.5で修正され、デフォルトで機能するようになっています。こちらをご覧ください

PUrify(この問題が発生した後)という新しいライブラリを作成しました。このライブラリは、この投稿のアプローチのバリエーションを通じて、.NET pre 4.5(3.5で動作)およびMonoで動作するように処理します。PUrifyはEscapeDataStringを変更しませんが、エスケープされない予約文字を含むUrisを使用できます。

于 2013-12-28T17:59:25.520 に答える
2

この質問と回答は数年前のものであることに気付きましたが、 .Net 4.5でコンプライアンスを取得するのに問題があったときに、自分の発見を共有したいと思いました。

コードがasp.netで実行されている場合、プロジェクトをターゲット4.5に設定し、4.5以降のマシンで実行すると、4.0の動作が発生する可能性があります。<httpRuntime targetFramework="4.5" />web.configでが設定されていることを確認する必要があります。

msdnに関するこのブログ記事から、

Web.configに属性が存在しない場合<httpRuntime targetFramework>、アプリケーションが4.0の癖の動作を望んでいたと想定します。

于 2016-12-09T20:08:30.187 に答える
0

どのバージョンのフレームワークを使用していますか?これらの変更の多くは、(MSDNから)「。NETFramework3.5。3.0SP1、および2.0SP1」の時間枠で行われたようです。

于 2009-05-11T04:04:42.017 に答える
0

より良い答え(100%フレームワークまたは100%再実装)を見つけることができなかったので、私はこの忌まわしきものを作成しました。OAuthを使用しているようです。

class al_RFC3986
{
    public static string Encode(string s)
    {
        StringBuilder sb = new StringBuilder(s.Length*2);//VERY rough estimate
        byte[] arr = Encoding.UTF8.GetBytes(s);

        for (int i = 0; i < arr.Length; i++)
        {
            byte c = arr[i];

            if(c >= 0x41 && c <=0x5A)//alpha
                sb.Append((char)c);
            else if(c >= 0x61 && c <=0x7A)//ALPHA
                sb.Append((char)c);
            else if(c >= 0x30 && c <=0x39)//123456789
                sb.Append((char)c);
            else if (c == '-' || c == '.' || c == '_' || c == '~')
                sb.Append((char)c);
            else
            {
                sb.Append('%');
                sb.Append(Convert.ToString(c, 16).ToUpper());
            }
        }
        return sb.ToString();
    }
}
于 2012-03-21T14:20:54.070 に答える