Streaming with WCF and MTOM

2019-02-07 11:14发布

问题:

I am using WCF bindings with streamed transfer mode, for both uploading and downloading binary content to/from a service. I've managed to get it working. I'll include the configuration, contracts, etc for reference.

I've made some tests to benchmark different bindings and encodings. Uploading results seems ok. NetTcp being the fastest, followed by BasicHttp-MTOM and then BasicHttp-Text. What suprises me is that, when downloading large files, MTOM is very slow as opposed to Text encoding with BasicHttp and Binary encoding with NetTcp.

Am I missing something? Why BasicHttp-MTOM works way slower than other bindings when uploading? Beside that I've implemented double buffering for downloads. This also works well with all bindings except BasicHttp with MTOM encoding. Why double buffering doesn't help when using MTOM?

Thanks for reading, your advice and ideas about this.

Test Results:

Uploading 150 MB binary data to service. Client creates a file stream from a 150 MB file and passes to server. Server reads the stream into a memory stream. No double buffer yet. Results seems fast as there is no writing of data to file system. And bindings perform as expected.

Downloading 100 MB binary data from service. Service creates a memory stream and passes to client. Client writes to file system. Here is the results with both single and double buffer. As you can see MTOM seems extremely slow and doesn't respond to double buffering as well.

Server configuration (left out some parts for simplicity):

<configuration>
  <system.web>
    <httpRuntime maxRequestLength="2147483647"/>
  </system.web>
  <system.serviceModel>
    <bindings>
      <netTcpBinding>
        <binding name="StreamedNetTcpBinding"
                 transferMode="Streamed"
                 maxReceivedMessageSize="1099511627776">
        </binding>
      </netTcpBinding>
      <basicHttpBinding>
        <binding name="StreamedBasicHttpBindingWithMtom"
                 messageEncoding="Mtom" transferMode="Streamed"
                 maxReceivedMessageSize="1099511627776">
        </binding>
        <binding name="StreamedBasicHttpBinding"
                 transferMode="Streamed"
                 maxReceivedMessageSize="1099511627776">
        </binding>
      </basicHttpBinding>
    </bindings>
  </system.serviceModel>
</configuration>

Client configuration (left out some parts for simplicity):

<configuration>
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="StreamedBasicHttpBindingWithMtom" 
                 maxReceivedMessageSize="1099511627776"
                 messageEncoding="Mtom" transferMode="Streamed">
        </binding>
        <binding name="StreamedBasicHttpBinding"
                 maxReceivedMessageSize="1099511627776"
                 transferMode="Streamed">
        </binding>
      </basicHttpBinding>
      <netTcpBinding>
        <binding name="StreamedNetTcpBinding" transferMode="Streamed"
          maxReceivedMessageSize="1099511627776">
        </binding>
      </netTcpBinding>
    </bindings>
  </system.serviceModel>
</configuration>

Service Contract:

[ServiceContract]
public interface IFileService
{
    [OperationContract]
    void UploadFile(DocumentData document);

    [OperationContract]
    DocumentData DownloadFile();
}

Message Contract:

[MessageContract]
public class DocumentData
{
    [MessageHeader(MustUnderstand = true)]
    public string DocumentName { get; set; }

    [MessageHeader(MustUnderstand = true)]
    public int FileLength { get; set; }

    [MessageBodyMember(Order = 1)]
    public Stream Data { get; set; }
}


Edit: This turned out to be an issue with my development environment setup at work. When I ran the same tests at home, the results was as expected.

回答1:

I'll add links that I used to implement streaming and accept this as an answer.

Progress Indication while Uploading/Downloading Files using WCF By Dimitris Papadimitriou
Implementation of double buffering while reading/writing from/to a stream. (See Thomas Levesque's answer)
Another implementation for double buffering, which does the same thing. (See Nicholas Carey's answer)
Return Stream from WCF service, using SqlFileStream

Working Sample Link