如何计算WCF服务器向客户端发送的消息流的大小

时间:2016-01-14 09:26:40

标签: c# .net wcf

从服务器端,有时我们发送的超大数据超出客户端NET TCP绑定中定义的限制。在这种情况下,我们在客户端获得通信异常。如果我在客户端增加绑定参数MaxReceivedMessageSize的大小,问题就会得到解决,但是我们不确定WCF服务器将向我们发送多少数据,并且它可以再次超过客户端MaxReceivedMessageSize中定义的限制。

有什么办法可以让我知道WCF服务器要发送给客户端的消息流的实际大小,这样如果大小超过客户端定义的大小,那么在发送之前,我可以修剪服务器端的消息内容达到该限制。

1 个答案:

答案 0 :(得分:0)

字节流的大小取决于所使用的编码器和不同编码器产生的不同大小的字节流。

我编写了一个MessageInspector,它执行消息/流重写以计算最终字节流的大小。在客户端中配置此检查器后,它将打印文本编码器与您配置的编码器(MTOM,二进制或GZip)创建的消息大小的差异。 Inspector的发送方法如下所示:

public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel)
{
  var mb = request.CreateBufferedCopy(int.MaxValue);  
  request = mb.CreateMessage();  
  var ms = new MemoryStream();

  // Dump message size based on text encoder.
  using (var memWriter = XmlDictionaryWriter.CreateTextWriter(ms))
  {
    mb.CreateMessage().WriteMessage(memWriter);
    memWriter.Flush();
    Console.WriteLine("Message size using text encoder {0}", ms.Position);
  }

  ms = new MemoryStream(); 

  if (gzipEncoding != null)
  {// GZip Special case
    var encoder = gzipEncoding.CreateMessageEncoderFactory().CreateSessionEncoder();
    encoder.WriteMessage(mb.CreateMessage(), ms);
    Console.WriteLine("GZip encoded size {0}", ms.Position);
    return null;
  }

  // just wrap the message – and wrapper will do the trick.

  request = new WrappingMessage(request);

  return null;
}

public class WrappingMessage : Message
{
  Message innerMsg;  
  MessageBuffer msgBuffer;

  public WrappingMessage(Message inner)
  {
    this.innerMsg = inner; 
    msgBuffer = innerMsg.CreateBufferedCopy(int.MaxValue); 
    innerMsg = msgBuffer.CreateMessage();
  }

  public override MessageHeaders Headers
  {
    get { return innerMsg.Headers; }
  }

  protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
  {
    innerMsg.WriteBodyContents(writer);
  }

  public override MessageProperties Properties
  {
    get { return innerMsg.Properties; }
  }

  public override MessageVersion Version
  {
    get { return innerMsg.Version; }
  }

  protected override void OnWriteMessage(XmlDictionaryWriter writer)
  {
    // write message to the actual stream using encoder..

    base.OnWriteMessage(writer); 
    writer.Flush();

    // write message to MemoryStream (using encoder) to get it’s size.
    var copy = msgBuffer.CreateMessage();
    DumpEncoderSize(writer, copy);
  }

  private static void DumpEncoderSize(System.Xml.XmlDictionaryWriter writer, Message copy)
  {
    var ms = new MemoryStream(); 
    string configuredEncoder = string.Empty; 
    if (writer is IXmlTextWriterInitializer)
    {
        var w = (IXmlTextWriterInitializer)writer; 
        w.SetOutput(ms, Encoding.UTF8, true); 
        configuredEncoder = "Text";
    }
    else if (writer is IXmlMtomWriterInitializer)
    {
      var w = (IXmlMtomWriterInitializer)writer;
      w.SetOutput(ms, Encoding.UTF8, int.MaxValue, "", null, null, true, false);
      configuredEncoder = "MTOM";
    }
    else if (writer is IXmlBinaryWriterInitializer)
    {
      var w = (IXmlBinaryWriterInitializer)writer;
      w.SetOutput(ms, null, null, false);
      configuredEncoder = "Binary";
    }

    copy.WriteMessage(writer);
    writer.Flush();
    var size = ms.Position;
    Console.WriteLine("Message size using configured ({1}) encoder {0}",  size,configuredEncoder);
  }
}