1

私はこれがうまくいかない理由を理解するために私の一日のほとんどを費やしました。オブジェクトをクライアントにストリーミングするWCFサービスがあります。次に、クライアントはファイルをディスクに書き込むことになっています。しかし、呼び出すstream.Read(buffer, 0, bufferLength)と常に0が返されます。コードは次のとおりです。

namespace StreamServiceNS
{
    [ServiceContract]
    public interface IStreamService
    {
        [OperationContract]
        Stream downloadStreamFile();
    }
}
class StreamService : IStreamService
{
    public Stream downloadStreamFile()
    {
        ISSSteamFile sFile = getStreamFile();
        BinaryFormatter bf = new BinaryFormatter();
        MemoryStream stream = new MemoryStream();
        bf.Serialize(stream, sFile);
        return stream;
    }
}

サービス構成ファイル:

<system.serviceModel>
<services>
  <service name="StreamServiceNS.StreamService">
    <endpoint address="stream" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IStreamService"
              name="BasicHttpEndpoint_IStreamService" contract="SWUpdaterService.ISWUService" />
  </service>
</services>
<bindings>
  <basicHttpBinding>
    <binding name="BasicHttpBinding_IStreamService" transferMode="StreamedResponse" 
             maxReceivedMessageSize="209715200"></binding>
  </basicHttpBinding>
</bindings>
<behaviors>
  <serviceBehaviors>
    <behavior>
      <serviceThrottling maxConcurrentCalls ="100" maxConcurrentSessions="400"/>
      <serviceMetadata httpGetEnabled="true"/>
      <serviceDebug includeExceptionDetailInFaults="false"/>
    </behavior>
  </serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>

クライアント:

TestApp.StreamServiceRef.StreamServiceClient client = new StreamServiceRef.StreamServiceClient();
        try
        {
            Stream stream = client.downloadStreamFile();
            int bufferLength = 8 * 1024;
            byte[] buffer = new byte[bufferLength];

            FileStream fs = new FileStream(@"C:\test\testFile.exe", FileMode.Create, FileAccess.Write);
            int bytesRead;
            while ((bytesRead = stream.Read(buffer, 0, bufferLength)) > 0)
            {
                fs.Write(buffer, 0, bytesRead);
            }
            stream.Close();
            fs.Close();
        }
        catch (Exception e) { Console.WriteLine("Error: " + e.Message); }

クライアントapp.config:

    <system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="BasicHttpEndpoint_IStreamService" maxReceivedMessageSize="209715200" transferMode="StreamedResponse">
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://[server]/StreamServices/streamservice.svc/stream"
            binding="basicHttpBinding" bindingConfiguration="BasicHttpEndpoint_IStreamService"
            contract="StreamServiceRef.IStreamService" name="BasicHttpEndpoint_IStreamService" />
    </client>
    </system.serviceModel>

(簡潔にするために一部のコードを切り取った)

WCFストリーミングサービスの作成で見つけたものをすべて読みましたが、私のコードはそれらのコードと何ら変わりはありません。ストリーミングをバッファリングに置き換えて、オブジェクトをそのようにうまく送信することはできますが、ストリーミングしようとすると、クライアントは常にストリームを「空」と見なします。が作成されますtestFile.exeが、サイズは0KBです。

私は何が欠けていますか?


Hrm
を更新 します。デバッグできません。デバッグしようとすると、WCFテストクライアントがストリームをサポートしていないことがわかります。しかし、whileループを配置せず、fs.Write(...)が1つしかない場合、ストリームが閉じると8KBが書き込まれるため、ストリーム内で何かが発生していることはわかっています。だから何かが伝わってきています。

私はあなたの投稿を見て、次のように追加しました。

[MessageContract]
public class FileDownloadMessage
{
    [MessageBodyMember(Order = 1)]
    public MemoryStream FileByteStream;
}

私のIStreamServiceに。そしてdownloadStreamFile()今、オブジェクトを返しFileDownloadMessageます。

しかし、クライアントのサービス参照を更新した後、オブジェクトdownloadStreamFile()を返すと考えています。 それはまた、私が作成しなかったクラスを作成し、それがどこから来ているのかわかりません。TestApp.StreamServiceRef.MemoryStream
downloadStreamFileRequest()

4

4 に答える 4

2

まず、サービスをデバッグして、ストリームがクライアントに送信される前に、その側にデータが含まれているかどうかを確認できますか?

WCF サービスからもストリームを返しています。同じ問題ではありませんが、私もそれに問題がありました。私が見つけた解決策が役立つことを願っています。ここで解決策を見つけました。このソリューションはストリームのアップロードを扱っていますが、私のダウンロード サービスでの実装はうまくいきました。
私のSOの質問/解決策はこちらです(私自身の回答は、AJAXに固有の受け入れられた回答ではなく、おそらく見るべきものです)

編集: 基本的な違いは、Stream を MessageContract でラップし、Stream をメッセージの唯一のメンバーとして指定し、basicHttp バインディングの「transferMode」属性が「Streamed」であることです。私は WCF を初めて使用するので、これが役立つかどうかはわかりませんが、役立つことを願っています!

編集 2 : サービス参照は使用しません。(cmd プロンプトから) 'svcutil.exe [mex url]' を実行して、サービス参照から取得したものよりも正確な構成ファイルと .cs ファイルを取得できます。私のプロジェクトにはサービス参照すらありませんが、正常に動作します。生成された .cs ファイルをプロジェクトに追加し、そのための 'using' ステートメントを追加するだけです。また、構成設定をクライアントのアプリまたは Web 構成ファイルに追加することもできます。生成されたこれら 2 つのファイルは、svcutil コマンドを実行したディレクトリに作成されます。

このクラスは、クライアントがサービスを呼び出すときにDownloadStreamFileRequest渡す単なる要求オブジェクトです。base.Channel以下の私のコードでは、それは呼び出されますGetExportedFileRequest

生成された .cs ファイルには、オブジェクトSystem.IO.MemoryStreamからこのストリームを返し、取得する次のメソッドがあります。FileDownloadMessage

public System.IO.MemoryStream GetExportedFile()
{
    GetExportedFileRequest inValue = new GetExportedFileRequest();
    FileDownloadMessage retVal = ((IDailyBillingParser)(this)).GetExportedFile( inValue );
    return retVal.FileByteStream;
}
于 2011-01-05T22:18:30.617 に答える
0

「 BinaryFormatter 」を使用したい理由はありますか?いいえの場合、次のように wcf からストリームを返すことができます

return new FileStream(@"D:\yourFileName.txt", FileMode.Open, FileAccess.Read)

于 2011-01-06T10:53:41.537 に答える