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

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

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

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

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

现有代码(种类)

var uploadData = new List(); 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())); 

问题

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

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

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

据我所知,HttpUtility(它有自己的编码/解码方法)不适用于紧凑的框架。

或者您可以简单地拆分字符串并为每个块调用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))); } } 
 StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < originalString.Length; i++) { if ((originalString[i] >= 'a' && originalString[i] <= 'z') || (originalString[i] >= 'A' && originalString[i] <= 'Z') || (originalString[i] >= '0' && originalString[i] <= '9')) { stringBuilder.Append(originalString[i]); } else { stringBuilder.AppendFormat("%{0:X2}", (int)originalString[i]); } } string result = stringBuilder.ToString(); 

我一直在使用System.Web.HttpUtility.UrlEncode,似乎更好地处理更长的字符串。

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

要测试这些function:

 var testString = "long string to encode"; var encodedString = EncodeString(testString); var decodedString = DecodeString(encodedString); Console.WriteLine(decodedString == testString ? "integrity respected" : "integrity broken"); 

希望这可以帮助避免一些头痛;)

使用System.Web.HttpUtility.UrlEncode (基于此答案 ):

  value = HttpUtility.UrlEncode(value) .Replace("!", "%21") .Replace("(", "%28") .Replace(")", "%29") .Replace("*", "%2A") .Replace("%7E", "~"); // undo escape