Uri.EscapeDataString() - 无效的URI:Uri字符串太长

ETF*_*fax 29 c# uri compact-framework exception-handling httpwebrequest

我在Windows Mobile上使用紧凑框架/ C#.

在我的应用程序中,我通过序列化对象并使用HttpWebRequest/POST请求将数据上传到服务器来上传数据.在服务器上,后置数据被反序列化并保存到数据库.

前几天我意识到我在帖子数据(&符号等)中遇到了特殊字符的问题.所以我在方法中引入了Uri.EscapeDataString(),一切都很顺利.

但是,今天我发现当应用程序尝试上传大量数据时出现问题(我不确定此刻究竟表示"大"的是什么!)

现有代码(种类)

var uploadData = new List<Things>();

uploadData.Add(new Thing() { Name = "Test 01" });
uploadData.Add(new Thing() { Name = "Test 02" });
uploadData.Add(new Thing() { Name = "Test with an & Ampersand " }); // Do this a lot!!

var postData = "uploadData=" + Uri.EscapeDataString(JsonConvert.SerializeObject(uploadData, new IsoDateTimeConverter()));
Run Code Online (Sandbox Code Playgroud)

问题

对Uri.EscapeDataString()的调用导致以下异常:

System.UriFormatException:无效的URI:Uri字符串太长.

有没有其他方法来准备上传数据?

据我所知,HttpUtility(它有自己的Encode/Decode方法)不适用于紧凑的框架.

Alb*_*ola 36

或者您可以简单地拆分字符串并调用Uri.EscapeDataString(string)每个块,以避免重新实现该功能.

示例代码:

        String value = "large string to encode";
        int limit = 2000;

        StringBuilder sb = new StringBuilder();
        int loops = value.Length / limit;

        for (int i = 0; i <= loops; i++)
        {
            if (i < loops)
            {
                sb.Append(Uri.EscapeDataString(value.Substring(limit * i, limit)));
            }
            else
            {
                sb.Append(Uri.EscapeDataString(value.Substring(limit * i)));
            }
        }
Run Code Online (Sandbox Code Playgroud)

  • EscapeDataString的.net 4.5限制为65520个字符 - 因此可用于减少所需的迭代次数. (5认同)
  • 只是一个更新:.NET 4.5中EscapeDataString的正确当前限制是32766个字符(不是上面@Knagi所提到的65520):https://msdn.microsoft.com/en-us/library/system.uri.escapedatastring%28v = vs.110%29.aspx (3认同)
  • @Nick,如果您实际尝试过,则可能会发现65520是实际限制(不包括,因此65519是最有效的限制),尽管文档中有说明。 (2认同)

Pou*_*uki 5

“Alberto de Paola”的答案很好。

尽管如此,要对转义数据进行转义有点棘手,因为您必须避免在编码字符的中间切割编码字符串(否则您将破坏原始字符串的完整性)。

这是我解决这个问题的方法:

public static string EncodeString(string str)
{
    //maxLengthAllowed .NET < 4.5 = 32765;
    //maxLengthAllowed .NET >= 4.5 = 65519;
    int maxLengthAllowed = 65519;
    StringBuilder sb = new StringBuilder();
    int loops = str.Length / maxLengthAllowed;

    for (int i = 0; i <= loops; i++)
    {
        sb.Append(Uri.EscapeDataString(i < loops
            ? str.Substring(maxLengthAllowed * i, maxLengthAllowed)
            : str.Substring(maxLengthAllowed * i)));
    }

    return sb.ToString();
}

public static string DecodeString(string encodedString)
{
    //maxLengthAllowed .NET < 4.5 = 32765;
    //maxLengthAllowed .NET >= 4.5 = 65519;
    int maxLengthAllowed = 65519;

    int charsProcessed = 0;
    StringBuilder sb = new StringBuilder();

    while (encodedString.Length > charsProcessed)
    {
        var stringToUnescape = encodedString.Substring(charsProcessed).Length > maxLengthAllowed
            ? encodedString.Substring(charsProcessed, maxLengthAllowed)
            : encodedString.Substring(charsProcessed);

        // If the loop cut an encoded tag (%xx), we cut before the encoded char to not loose the entire char for decoding
        var incorrectStrPos = stringToUnescape.Length == maxLengthAllowed ? stringToUnescape.IndexOf("%", stringToUnescape.Length - 4, StringComparison.InvariantCulture) : -1;
        if (incorrectStrPos > -1)
        {
            stringToUnescape = encodedString.Substring(charsProcessed).Length > incorrectStrPos
                ? encodedString.Substring(charsProcessed, incorrectStrPos)
                : encodedString.Substring(charsProcessed);
        }

        sb.Append(Uri.UnescapeDataString(stringToUnescape));
        charsProcessed += stringToUnescape.Length;
    }

    var decodedString = sb.ToString();

    // ensure the string is sanitized here or throw exception if XSS / SQL Injection is found
    SQLHelper.SecureString(decodedString);
    return decodedString;
}
Run Code Online (Sandbox Code Playgroud)

要测试这些功能:

var testString = "long string to encode";
var encodedString = EncodeString(testString);
var decodedString = DecodeString(encodedString);

Console.WriteLine(decodedString == testString ? "integrity respected" : "integrity broken");
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助避免一些令人头痛的问题;)