none
How to limit WCF Response Size

    Question

  • Hi,

    is there any limit way to limit the size of response from wcf service?

    I am not talking about the client configuration like maxreceivedresponsesize?

    Thanks,

    Prakash

    Thursday, January 20, 2011 5:54 AM

Answers

  • Besides adding code into the service itself to limit the response as Richard mentioned, you can also add a custom encoder in your binding which will do it for all operations, essentially creating a "MaxSentMessageSize" quota, as shown in the example below.

      public class Post_6569a13e_c2a0_4440_ab97_c5c6b753737a
      {
        [ServiceContract]
        public interface ITest
        {
          [OperationContract]
          string Echo(string input);
        }
        public class Service : ITest
        {
          public string Echo(string input)
          {
            return input;
          }
        }
    
        class MyResponseSizeLimitingEncodingBindingElement : MessageEncodingBindingElement
        {
          int maxSentMessageSize;
          MessageEncodingBindingElement inner;
          public MyResponseSizeLimitingEncodingBindingElement(MessageEncodingBindingElement inner, int maxSentMessageSize)
          {
            this.maxSentMessageSize = maxSentMessageSize;
            this.inner = inner;
          }
          public override MessageEncoderFactory CreateMessageEncoderFactory()
          {
            return new MyResponseSizeLimitingEncoderFactory(this.inner.CreateMessageEncoderFactory(), this.maxSentMessageSize);
          }
    
          public override MessageVersion MessageVersion
          {
            get { return this.inner.MessageVersion; }
            set { this.inner.MessageVersion = value; }
          }
    
          public override BindingElement Clone()
          {
            return new MyResponseSizeLimitingEncodingBindingElement((MessageEncodingBindingElement)this.inner.Clone(), this.maxSentMessageSize);
          }
    
          public override bool CanBuildChannelListener<TChannel>(BindingContext context)
          {
            return this.inner.CanBuildChannelListener<TChannel>(context);
          }
    
          public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
          {
            context.BindingParameters.Add(this);
            return context.BuildInnerChannelListener<TChannel>();
          }
    
          class MyResponseSizeLimitingEncoderFactory : MessageEncoderFactory
          {
            int maxSentMessageSize;
            MessageEncoderFactory inner;
            public MyResponseSizeLimitingEncoderFactory(MessageEncoderFactory inner, int maxSentMessageSize)
            {
              this.maxSentMessageSize = maxSentMessageSize;
              this.inner = inner;
            }
    
            public override MessageEncoder Encoder
            {
              get { return new MyResponseSizeLimitingEncoder(this.inner.Encoder, this.maxSentMessageSize); }
            }
    
            public override MessageVersion MessageVersion
            {
              get { return this.inner.MessageVersion; }
            }
          }
    
          class MyResponseSizeLimitingEncoder : MessageEncoder
          {
            int maxSentMessageSize;
            MessageEncoder inner;
    
            public MyResponseSizeLimitingEncoder(MessageEncoder inner, int maxSentMessageSize)
            {
              this.maxSentMessageSize = maxSentMessageSize;
              this.inner = inner;
            }
    
            public override string ContentType
            {
              get { return this.inner.ContentType; }
            }
    
            public override string MediaType
            {
              get { return this.inner.MediaType; }
            }
    
            public override MessageVersion MessageVersion
            {
              get { return this.inner.MessageVersion; }
            }
    
            public override bool IsContentTypeSupported(string contentType)
            {
              return this.inner.IsContentTypeSupported(contentType);
            }
    
            public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
            {
              return this.inner.ReadMessage(buffer, bufferManager, contentType);
            }
    
            public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
            {
              return this.inner.ReadMessage(stream, maxSizeOfHeaders, contentType);
            }
    
            public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
            {
              ArraySegment<byte> result = this.inner.WriteMessage(message, maxMessageSize, bufferManager, messageOffset);
              int messageSize = result.Offset + result.Count;
              Console.WriteLine("Return message size: {0}", messageSize);
              if (messageSize > this.maxSentMessageSize)
              {
                // This is a quick/dirty solution. This will simply cause the server to abort the socket,
                // and the client will receive a generic "socket abort exception"
                //
                // Another solution would be for this encoder to produce a fault or some
                // response which the client can understand.
                Console.WriteLine("Message size ({0}) is greater than MaxSentMessageSize ({1})", messageSize, this.maxSentMessageSize);
                throw new InvalidOperationException("MaxSentMessageSize exceeded");
              }
    
              return result;
            }
    
            public override void WriteMessage(Message message, Stream stream)
            {
              // To implement this, wrap the stream with a "CountingStream", which would throw if
              // its size grew past MaxSentMessageSize.
              throw new NotImplementedException();
            }
          }
        }
    
        static Binding GetBinding(bool server)
        {
          BasicHttpBinding result = new BasicHttpBinding();
          if (server)
          {
            CustomBinding custom = new CustomBinding(result);
            for (int i = 0; i < custom.Elements.Count; i++)
            {
              MessageEncodingBindingElement mebe = custom.Elements[i] as MessageEncodingBindingElement;
              if (mebe != null)
              {
                custom.Elements[i] = new MyResponseSizeLimitingEncodingBindingElement(mebe, 1000);
                break;
              }
            }
    
            return custom;
          }
          else
          {
            return result;
          }
        }
        public static void Test()
        {
          string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
          ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
          host.AddServiceEndpoint(typeof(ITest), GetBinding(true), "");
          host.Open();
          Console.WriteLine("Host opened");
    
          ChannelFactory<ITest> factory = new ChannelFactory<ITest>(GetBinding(false), new EndpointAddress(baseAddress));
          ITest proxy = factory.CreateChannel();
          Console.WriteLine(proxy.Echo("Hello"));
          Console.WriteLine(proxy.Echo(new string('r', 800)));
          try
          {
            Console.WriteLine(proxy.Echo(new string('r', 1000)));
          }
          catch (Exception e)
          {
            Console.WriteLine("{0}: {1}", e.GetType().FullName, e.Message);
            Exception inner = e.InnerException;
            while (inner != null)
            {
              Console.WriteLine("  {0}: {1}", inner.GetType().FullName, inner.Message);
              inner = inner.InnerException;
            }
          }
    
          ((IClientChannel)proxy).Close();
          factory.Close();
    
          Console.Write("Press ENTER to close the host");
          Console.ReadLine();
          host.Close();
        }
      }
    
    
    • Proposed as answer by Carlos Figueira Monday, January 24, 2011 11:27 PM
    • Marked as answer by Yi-Lun Luo Wednesday, January 26, 2011 9:15 AM
    Thursday, January 20, 2011 5:45 PM

All replies

  • not through configuration. The service is in control of how much data it sends for a request you should code any limits into the service.

    If the infrastructure truncated the data then the data might be unusable (end up as non-well formed XML for example)


    Richard Blewett, thinktecture - http://www.dotnetconsult.co.uk/weblog2
    Twitter: richardblewett
    Thursday, January 20, 2011 8:49 AM
    Moderator
  • Besides adding code into the service itself to limit the response as Richard mentioned, you can also add a custom encoder in your binding which will do it for all operations, essentially creating a "MaxSentMessageSize" quota, as shown in the example below.

      public class Post_6569a13e_c2a0_4440_ab97_c5c6b753737a
      {
        [ServiceContract]
        public interface ITest
        {
          [OperationContract]
          string Echo(string input);
        }
        public class Service : ITest
        {
          public string Echo(string input)
          {
            return input;
          }
        }
    
        class MyResponseSizeLimitingEncodingBindingElement : MessageEncodingBindingElement
        {
          int maxSentMessageSize;
          MessageEncodingBindingElement inner;
          public MyResponseSizeLimitingEncodingBindingElement(MessageEncodingBindingElement inner, int maxSentMessageSize)
          {
            this.maxSentMessageSize = maxSentMessageSize;
            this.inner = inner;
          }
          public override MessageEncoderFactory CreateMessageEncoderFactory()
          {
            return new MyResponseSizeLimitingEncoderFactory(this.inner.CreateMessageEncoderFactory(), this.maxSentMessageSize);
          }
    
          public override MessageVersion MessageVersion
          {
            get { return this.inner.MessageVersion; }
            set { this.inner.MessageVersion = value; }
          }
    
          public override BindingElement Clone()
          {
            return new MyResponseSizeLimitingEncodingBindingElement((MessageEncodingBindingElement)this.inner.Clone(), this.maxSentMessageSize);
          }
    
          public override bool CanBuildChannelListener<TChannel>(BindingContext context)
          {
            return this.inner.CanBuildChannelListener<TChannel>(context);
          }
    
          public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
          {
            context.BindingParameters.Add(this);
            return context.BuildInnerChannelListener<TChannel>();
          }
    
          class MyResponseSizeLimitingEncoderFactory : MessageEncoderFactory
          {
            int maxSentMessageSize;
            MessageEncoderFactory inner;
            public MyResponseSizeLimitingEncoderFactory(MessageEncoderFactory inner, int maxSentMessageSize)
            {
              this.maxSentMessageSize = maxSentMessageSize;
              this.inner = inner;
            }
    
            public override MessageEncoder Encoder
            {
              get { return new MyResponseSizeLimitingEncoder(this.inner.Encoder, this.maxSentMessageSize); }
            }
    
            public override MessageVersion MessageVersion
            {
              get { return this.inner.MessageVersion; }
            }
          }
    
          class MyResponseSizeLimitingEncoder : MessageEncoder
          {
            int maxSentMessageSize;
            MessageEncoder inner;
    
            public MyResponseSizeLimitingEncoder(MessageEncoder inner, int maxSentMessageSize)
            {
              this.maxSentMessageSize = maxSentMessageSize;
              this.inner = inner;
            }
    
            public override string ContentType
            {
              get { return this.inner.ContentType; }
            }
    
            public override string MediaType
            {
              get { return this.inner.MediaType; }
            }
    
            public override MessageVersion MessageVersion
            {
              get { return this.inner.MessageVersion; }
            }
    
            public override bool IsContentTypeSupported(string contentType)
            {
              return this.inner.IsContentTypeSupported(contentType);
            }
    
            public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
            {
              return this.inner.ReadMessage(buffer, bufferManager, contentType);
            }
    
            public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
            {
              return this.inner.ReadMessage(stream, maxSizeOfHeaders, contentType);
            }
    
            public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
            {
              ArraySegment<byte> result = this.inner.WriteMessage(message, maxMessageSize, bufferManager, messageOffset);
              int messageSize = result.Offset + result.Count;
              Console.WriteLine("Return message size: {0}", messageSize);
              if (messageSize > this.maxSentMessageSize)
              {
                // This is a quick/dirty solution. This will simply cause the server to abort the socket,
                // and the client will receive a generic "socket abort exception"
                //
                // Another solution would be for this encoder to produce a fault or some
                // response which the client can understand.
                Console.WriteLine("Message size ({0}) is greater than MaxSentMessageSize ({1})", messageSize, this.maxSentMessageSize);
                throw new InvalidOperationException("MaxSentMessageSize exceeded");
              }
    
              return result;
            }
    
            public override void WriteMessage(Message message, Stream stream)
            {
              // To implement this, wrap the stream with a "CountingStream", which would throw if
              // its size grew past MaxSentMessageSize.
              throw new NotImplementedException();
            }
          }
        }
    
        static Binding GetBinding(bool server)
        {
          BasicHttpBinding result = new BasicHttpBinding();
          if (server)
          {
            CustomBinding custom = new CustomBinding(result);
            for (int i = 0; i < custom.Elements.Count; i++)
            {
              MessageEncodingBindingElement mebe = custom.Elements[i] as MessageEncodingBindingElement;
              if (mebe != null)
              {
                custom.Elements[i] = new MyResponseSizeLimitingEncodingBindingElement(mebe, 1000);
                break;
              }
            }
    
            return custom;
          }
          else
          {
            return result;
          }
        }
        public static void Test()
        {
          string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
          ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
          host.AddServiceEndpoint(typeof(ITest), GetBinding(true), "");
          host.Open();
          Console.WriteLine("Host opened");
    
          ChannelFactory<ITest> factory = new ChannelFactory<ITest>(GetBinding(false), new EndpointAddress(baseAddress));
          ITest proxy = factory.CreateChannel();
          Console.WriteLine(proxy.Echo("Hello"));
          Console.WriteLine(proxy.Echo(new string('r', 800)));
          try
          {
            Console.WriteLine(proxy.Echo(new string('r', 1000)));
          }
          catch (Exception e)
          {
            Console.WriteLine("{0}: {1}", e.GetType().FullName, e.Message);
            Exception inner = e.InnerException;
            while (inner != null)
            {
              Console.WriteLine("  {0}: {1}", inner.GetType().FullName, inner.Message);
              inner = inner.InnerException;
            }
          }
    
          ((IClientChannel)proxy).Close();
          factory.Close();
    
          Console.Write("Press ENTER to close the host");
          Console.ReadLine();
          host.Close();
        }
      }
    
    
    • Proposed as answer by Carlos Figueira Monday, January 24, 2011 11:27 PM
    • Marked as answer by Yi-Lun Luo Wednesday, January 26, 2011 9:15 AM
    Thursday, January 20, 2011 5:45 PM