简体   繁体   中英

WCF Streaming mode doesn't seem to be streaming

I've been trying to build out an example of WCF streaming just for testing purposes and I can't be sure that it's actually streaming.

The sample is very basic:

  1. Server returns large binary content (PDF file in this case)
  2. Client writes large binary content to file.

However, the issue seems that even though I believe I've correctly configured both the server and client for streaming transfers:

  1. It does not appear to actually be a streaming transfer because I'm running into IOException with the message The maximum message size quota for incoming messages (65536) has been exceeded
  2. The reads are in increments of 1536 bytes, even when I set my stream buffer to 8192 (or any other size)

The full host code is here:

using System;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace WcfStreamingHost
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            BasicHttpBinding binding = new BasicHttpBinding();
            binding.TransferMode = TransferMode.Streamed;
            binding.MaxBufferSize = 65536;
            binding.MaxReceivedMessageSize = 65536;
            binding.ReaderQuotas.MaxBytesPerRead = 65536;
            binding.SendTimeout = TimeSpan.FromMinutes(10);

            ServiceHost host = new ServiceHost(typeof (ContentProvider), new Uri("http://charles-m4600:1234/contentprovider"));

            host.Description.Behaviors.Add(new ServiceMetadataBehavior());
            host.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;
            host.AddServiceEndpoint(typeof (IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
            host.AddServiceEndpoint(typeof (IContentProvider), binding, "streamed");

            host.Open();

            Console.ReadKey();
        }
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
    public class ContentProvider : IContentProvider
    {
        #region IContentProvider Members

        [OperationBehavior(AutoDisposeParameters = true)]
        public Stream GetFile()
        {
            Stream stream = File.OpenRead("large_file.pdf");

            return stream;
        }

        #endregion
    }

    [ServiceContract]
    public interface IContentProvider
    {
        [OperationContract]
        Stream GetFile();
    }
}

And the full client code is here:

using System;
using System.IO;
using System.ServiceModel;
using WcfStreamingClient.LocalSvc;

namespace WcfStreamingClient
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            BasicHttpBinding binding = new BasicHttpBinding();
            binding.TransferMode = TransferMode.Streamed;
            binding.MaxBufferSize = 65536;
            binding.MaxReceivedMessageSize = 65536;
            binding.ReaderQuotas.MaxBytesPerRead = 65536;
            binding.ReceiveTimeout = TimeSpan.FromMinutes(10);

            EndpointAddress address = new EndpointAddress("http://charles-m4600:1234/contentprovider/streamed");

            using (ContentProviderClient client = new ContentProviderClient(binding, address))
            {
                using (Stream stream = client.GetFile())
                {
                    FileInfo file = new FileInfo("output.pdf");

                    if (file.Exists)
                    {
                        file.Delete();
                    }

                    using (FileStream fileStream = file.Create())
                    {
                        const int bufferLen = 8192;
                        byte[] buffer = new byte[bufferLen];
                        int count = 0;
                        int total = 0;
                        while ((count = stream.Read(buffer, 0, bufferLen)) > 0)
                        {
                            fileStream.Write(buffer, 0, count);
                            total += count;
                            Console.Out.WriteLine("Read {0} bytes", total);
                        }
                    }
                }
            }
        }
    }
}

I've read through various other posts on this issue, but cannot seem to find any clues.

Although your post was quite some time ago, I stumbled upon it and thought I'd share my findings.

The maximum message size quota is always considered . No matter if you have a streamed transfer or not. MSDN is quite clear about it. The maximum buffer size can be specified additionally.

http://msdn.microsoft.com/en-us/library/ms731078%28v=vs.100%29.aspx

MaxReceivedMessageSize : Maximum size, in bytes, of a received message, including headers, before the transport raises an exception.

MaxBufferSize : Maximum size, in bytes, of a buffer used for streaming data. If this transport quota is not set, or the transport is not using streaming, then the quota value is the same as the smaller of the MaxReceivedMessageSize quota value and MaxValue.

Why you always have chunks of 1536 bytes , I am not totally sure of. But I think it is because of the maximum size of an ethernet frame (except jumbo frames):

http://en.wikipedia.org/wiki/Ethernet_frame

MaxReceivedMessageSize is there to prevent DOS attack on incomming channesl and MaxBufferSize controls message buffersize on channel.When channel is configured for streaming only soap header get buffered and body is streamed, Stream chunk size is control by service implementation (8Kb in your case), and maxrecievedmessagesize bounds size of file+header. maxrecieved message size must be equal to size of file MaxBufferSize in buffering mode. But in streaming MaxBufferSize must be small and MaxRecievedMessafeSize expected file size.In streaming mode MaxBufferSize can be used to prevent DOS attack.

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