2011-07-14 51 views
25

Windows Mobileでコンパクトフレームワーク/ C#を使用しています。私のアプリケーションでUri.EscapeDataString() - 無効なURI:Uri文字列が長すぎます

私は、オブジェクトをシリアル化して情報を送信するためのHttpWebRequest/POSTリクエストを使用してサーバーにデータをアップロードしています。サーバー上で、ポストデータはデシリアライズされ、dbに保存されます。

私はポストデータに特殊文字に問題があったことに気づいた他の日(アンパサンド等。)。そこで私は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())); 

通報

Uri.EscapeDataString()の呼び出し、次の例外を引き起こしている。

System.UriFormatException:無効なURI:URI文字列が長すぎます。

質問

は、アップロード用のデータを準備する他の方法はありますか?

は、私の知る限り(独自エンコード/デコード方法を有する)HttpUtilityを見ることができるように、コンパクトなフレームワークでは使用できません。

+1

あなたはあなた自身の実装だと書くことができますか? 'EscapeDataString()'はほとんど納得がいくようです...エスケープする必要がある文字のライブラリに基づいて、通常の 'String.Replace'を行いますか? – Smudge202

+0

Msdnの状態:UriFormatException - stringToEscapeの長さが32766文字を超えています。 – fluent

+0

Smudge202が示唆したように、私は自分の実装を書いただけです。 – ETFairfax

答えて

30

それとも単にあなたの文字列を分割して機能を再実装避けるために、各ブロックごとにUri.EscapeDataString(string)を呼び出すことができます。

サンプルコード:私はSystem.Web.HttpUtility.UrlEncodeを使用し、より良いより長い文字列を扱うように思われてきた

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

EscapeDataStringの.net 4.5の制限は65520文字です。これにより、必要な反復回数を減らすことができます。 –

+0

Cool。 Uri.Unescapeにはこの種の問題がありますか? –

+0

@Knagisなぜ実行時間の大きな部分になることはほとんどないので、ここで繰り返し回数を述べるのか分かりません。 value.LengthのサイズでStringBuilderを初期化すると、パフォーマンスが向上します。 –

1
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(); 
0

「アルベルト・デ・パオラ」の答えが良いです。

エスケープされたデータをエスケープするには、コード化された文字の途中でエンコードされた文字列をカットしないでください(または元の文字列の完全性が損なわれるため)。

ここでは、この問題を修正する私の方法です:

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

これらの関数をテストするには:これは、いくつかの頭痛を回避することができます

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

Console.WriteLine(decodedString == testString ? "integrity respected" : "integrity broken"); 

ホープ;)

0

this answerに基づいて使用System.Web.HttpUtility.UrlEncode( ):

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