简体   繁体   中英

WCF Client is Buffering with Streamed Transfer Mode

My end goal is to enable upload of large video files and streams to a WCF service which is configured for Streamed transfer mode. The problem I have is that my WCF client is only issuing a request to the service after the stream had been read to the end.

A primary use case would be relaying live streams to the service which have no predefined ending point, so it is not practical to fully read these streams before sending any data. To test this functionality, I have created an 'infinite' stream:

public class InfiniteStream : Stream
{
    private Random _random;

    public InfiniteStream()
    {
        _random = new Random(1);
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        _random.NextBytes(buffer);
        Position += count;
        return count;
    }

    // other unimportant methods
}

And consistent with examples I've found, a MessageContract for receiving the Streamed upload:

[MessageContract]
public class ClipUpload : IDisposable
{
    [MessageHeader(MustUnderstand = true)]
    public long MediaId;

    [MessageBodyMember(Order=1)]
    public System.IO.Stream MediaStream;

    // disposable implementaton
}

Now, as far as I can tell, my service is properly configured for streamed transfers and the stream can be read on the server-side without issue. Server config of interest:

<basicHttpsBinding>
    <binding name="A" transferMode="Streamed" maxReceivedMessageSize="4294967296" maxBufferSize="65536">
        <security mode="TransportWithMessageCredential">
            <message clientCredentialType="UserName" />
        </security>
    </binding>
</basicHttpsBinding>

Client config of interest:

<basicHttpsBinding>
    <binding name="A" transferMode="Streamed" maxBufferSize="65536">
        <security mode="TransportWithMessageCredential" />
    </binding>
</basicHttpsBinding>

The server-side operation is simple. In my service interface::

[OperationContract(IsOneWay=true)]
void UploadClip(ClipUpload upload);

Implementation:

public void UploadClip(ClipUpload upload)
{
    using (var stream = new FileStream(@"C:\Temp\temp.mp4", FileMode.Create, FileAccess.Write))
    {
        upload.MediaStream.CopyTo(stream);
    }

The client is also using a simple call:

using(var stream = new InfiniteStream())
{
    _service.UploadClip(1, stream);
}

Again, the issue is that the client is not sending any of the stream data until the stream is fully read, which of course will never be the case for InfiniteStream. Thus, flow never reaches the server's UploadClip method. For non-"infinite" streams, the process works, but there is a considerable delay while the client is seemingly buffering all of the stream content.

It seems that Fiddler may have been introducing its own buffer. With Fiddler closed, streamed requests were properly handed off to WCF.

On a related note, on it seems that on .NET 4.0 and lower, server-side buffering for streamed WCF services that are hosted in IIS is unavoidable. The ASP.NET layer has its own buffering mechanism which waits until the message is fully received before passing it off to WCF. More details here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM