2

私は .NET、C#、および WCF の初心者であり、大量のオブジェクト (オブジェクトの配列) のアップロードとダウンロードを可能にするメソッドを公開するサービスを作成しようとしています。WCF での大規模なファイル転送に関する多くの投稿を見てきましたが、大量のシリアル化可能なオブジェクトのアップロードとダウンロードだけに焦点を当てたものを見つけることができないようです。

WCF許可されたバイト数やタイムアウト制限などについて web.config ファイルを「ハック」することができましたが、そのような送信を可能にするために、速度とメモリ使用量を改善するために実際に構成するより良い方法があるかどうか疑問に思っています。テスト結果に基づいて web.settings を構成したため (タイムアウト/バイト制限を超えた場合、非常に大きな数値で制限を増やすなど)、構成がまったく意味を成しているとは思えません。

次に、 binding などの実装オプションをいくつか見てきTransferMode = Streaming or MTOMましたが、それらが私のシナリオに適用されるかどうかはまったくわかりません。誰かが私を正しい方向に向けることができますか?

申し訳ありませんが、質問を十分に構成できていない可能性がありますが、アイデアをいただければ幸いです。

以下は私のweb.config設定です:

<system.web>
    <httpRuntime maxRequestLength="409600000" executionTimeout="360000"/>
    <compilation debug="true" targetFramework="4.0"  />
  </system.web>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHTTP" closeTimeout="00:01:00" receiveTimeout="01:00:00"
          sendTimeout="01:00:00" maxBufferSize="655360000" maxReceivedMessageSize="655360000"
          messageEncoding="Text" />
      </basicHttpBinding>
    </bindings>
    <services>
      <service behaviorConfiguration="ServiceBehavior" name="WebService.WebService">
        <endpoint address="" behaviorConfiguration="BasicEndPoint" binding="basicHttpBinding"
          bindingConfiguration="BasicHTTP" name="BasicHTTP" contract="WebService.IWebService" />
      </service>
    </services>
    <behaviors>
      <endpointBehaviors>
        <behavior name="BasicEndPoint">
          <dataContractSerializer maxItemsInObjectGraph="65536000" />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true"  />
  </system.serviceModel>
 <system.webServer>
   <security>
     <requestFiltering>
       <requestLimits maxAllowedContentLength="204800000" />
     </requestFiltering>
   </security>
    <modules runAllManagedModulesForAllRequests="true" />
  </system.webServer>
4

2 に答える 2

1

ホストにストリームがあり、クライアントでストリームを受信する必要がある場合は、ビデオ/オーディオ ストリーミングなどのタスクにのみストリーム モードを使用することをお勧めします。他のタスクでは、バッファ モードを使用します。これは、非常に使いやすく、多くの便利な wcf 機能がバッファリングに依存しているためです。たとえば、SOAP メッセージ レベルのセキュリティを有効にしてストリーミングを使用すると、おそらくストリーミング モードの速度のメリットが失われる可能性があります (もしあれば)。

あなたの場合、いくつかの回避策を実行することをお勧めします。次の手順を確認してください。

  • 圧縮を使用してみてください。速度とリソース使用率を大幅に向上させることができますが、データ量が常に同じであることを保証することはできません。アレイが来年 100 倍大きくなるかどうかは誰にもわかりません。したがって、1 年後にこの時点に戻ることができます。
  • 1 つの巨大な配列を返すメソッドを、1 つの要素またはそれらの小さな範囲のみを返すメソッドに置き換えます。次に、1 回のGetAllStuff()メソッド呼び出しをGetItemsCountForDownload()の 1 回の呼び出しと適切な回数のGetElementAtIndex(int index) (またはGetElementsRange(int startIndex,int endIndex) ) の呼び出しに置き換えます。とにかく、この時点で、(各呼び出しの) メッセージ サイズと実行される呼び出しの数とのバランスを見つける必要があります。
  • データを小さな等しい部分に簡単に分割できない場合 (たとえば、配列の最初の要素が 10kb、2 番目の要素が 15 kb、3 番目が 338mb の場合) は、両方の方法を組み合わせてみてください: 配列をディスクにシリアル化し、分割して圧縮します。許容できるサイズのパーツをいくつか取り出して、それらを次々に転送します。
  • アルゴリズムのパラメータを調整できるようにしてください。それらを構成ファイルに入れて、利用可能なリソースに応じて、すべての展開マシンで分割プロセスと圧縮レベルを調整できるようにします。
  • データを分割し、チャンクごとにダウンロードすることのもう 1 つの利点は、エラー処理レイヤーを簡単に構築できることです。接続が不安定で、何らかの理由で転送に失敗した場合は、すべてのデータではなく、1 つのチャンクだけを再ダウンロードしてみてください。

アーキテクチャに関するいくつかのヒント

  • 適切なクロスプラットフォーム圧縮アルゴリズムを見つけます。きっとあなたのニーズに合った1台が見つかります。C# <-> Python の BZip2 と C # <-> Java の GZip を見てください。
  • アーキテクチャを他のプログラマにとって十分に明確にするようにしてください。圧縮データ転送用と非圧縮データ転送用に異なるメソッドを作成できます ( GetElementsRangeGetElementsRangeGZipGetElementsRangeBZip2 )。または、圧縮型パラメーター ( GetElementsRange(int startIndex,int endIndex,string compressionType ) を使用して 1 つのメソッドを作成することもできます。とにかく、他のプログラマーは、受信しているデータと圧縮モードの制御方法を理解できなければなりません。
  • データ分割パラメーターを構成ファイルからメソッド定義に移動できるため、クライアントは自分で定義できます。
  • さらに進んで、2 段階のアーキテクチャを実装できます。ステップ 1: リモート クライアントがリクエストのパラメータを定義します (圧縮モード、分割モード、その他すべてを含むすべてのパラメータ)。ステップ 2: データの受信。トークンはどうですか?メソッドは次のようになります。

    string GetTokenForDataRequest(string compressionMode, int maxChunkSize); //additional parameters like dates range, account number an other are defined in this method only
    int GetChunkCount(string token);
    byte[] GetDataChunkAtIndex(string token, int index);
    

ここで、 compressionMode は "None"、"BZip2"、または "GZip" です。maxChunkSizeが 0 の場合は、分割を無効にします (すべてのデータが 1 つのチャンクで送信されます)。それ以外の場合は、データをmaxChunkSizeに等しいサイズのチャンクに分割します(最後の 1 つは他よりも小さくなります)。したがって、おおよそのシナリオは次のようになります。

  1. リモート クライアントは、必要なパラメータを含むデータ リクエストを送信します。
  2. セッション ID (トークン) を生成し、このセッションのパラメーターを保存し、パラメーターに従ってデータを準備します。「データの準備」とは、要求に応じてデータをロードし、一時フォルダーを作成し、データをシリアライズし、チャンク ファイルを作成し、さらに使用するためにパスを永続化することを意味します。
  3. クライアントは、データを取得するための他のすべての方法で使用されるトークンを受け取ります。
  4. リモート クライアントがメソッドを通じてデータ チャンクを要求するたびに、提供されたトークンと永続化された情報により、データがハードディスクのどこに保存されているか、残っているチャンクの数などを知ることができます。
  5. 一度に複数のクライアントとの同時データ転送セッションを簡単に処理できます (データ チャンクを異なる一時ファイルとフォルダーに保存することを確認してください)。
  6. クライアントは任意のチャンクを再ダウンロードでき、データベースから (またはどこからでも) データをロードする必要はありません。
  7. 転送が完了したら、一時データを消去し、一部のリソースを解放できます。

これを唯一の可能な解決策と見なさないでください。少しググってみるだけで、自分のタスクを解決する独自の方法が見つかります。

于 2012-08-08T07:30:00.677 に答える
0

ストリーミングメッセージ転送を使用できますが、いくつかの制限があります。
ストリーミングが適切でない場合は、データのページングを実装できます (または、WCF Data Servicesのように既存の実装を試してください)。

于 2012-08-08T07:20:29.500 に答える