BufferedMessageWriter.cs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Channels
  5. {
  6. using System.IO;
  7. using System.Xml;
  8. using System.Diagnostics;
  9. abstract class BufferedMessageWriter
  10. {
  11. int[] sizeHistory;
  12. int sizeHistoryIndex;
  13. const int sizeHistoryCount = 4;
  14. const int expectedSizeVariance = 256;
  15. BufferManagerOutputStream stream;
  16. public BufferedMessageWriter()
  17. {
  18. this.stream = new BufferManagerOutputStream(SR.MaxSentMessageSizeExceeded);
  19. InitMessagePredicter();
  20. }
  21. protected abstract XmlDictionaryWriter TakeXmlWriter(Stream stream);
  22. protected abstract void ReturnXmlWriter(XmlDictionaryWriter writer);
  23. public ArraySegment<byte> WriteMessage(Message message, BufferManager bufferManager, int initialOffset, int maxSizeQuota)
  24. {
  25. int effectiveMaxSize;
  26. // make sure that maxSize has room for initialOffset without overflowing, since
  27. // the effective buffer size is message size + initialOffset
  28. if (maxSizeQuota <= int.MaxValue - initialOffset)
  29. effectiveMaxSize = maxSizeQuota + initialOffset;
  30. else
  31. effectiveMaxSize = int.MaxValue;
  32. int predictedMessageSize = PredictMessageSize();
  33. if (predictedMessageSize > effectiveMaxSize)
  34. predictedMessageSize = effectiveMaxSize;
  35. else if (predictedMessageSize < initialOffset)
  36. predictedMessageSize = initialOffset;
  37. try
  38. {
  39. stream.Init(predictedMessageSize, maxSizeQuota, effectiveMaxSize, bufferManager);
  40. stream.Skip(initialOffset);
  41. XmlDictionaryWriter writer = TakeXmlWriter(stream);
  42. OnWriteStartMessage(writer);
  43. message.WriteMessage(writer);
  44. OnWriteEndMessage(writer);
  45. writer.Flush();
  46. ReturnXmlWriter(writer);
  47. int size;
  48. byte[] buffer = stream.ToArray(out size);
  49. RecordActualMessageSize(size);
  50. return new ArraySegment<byte>(buffer, initialOffset, size - initialOffset);
  51. }
  52. finally
  53. {
  54. stream.Clear();
  55. }
  56. }
  57. protected virtual void OnWriteStartMessage(XmlDictionaryWriter writer)
  58. {
  59. }
  60. protected virtual void OnWriteEndMessage(XmlDictionaryWriter writer)
  61. {
  62. }
  63. void InitMessagePredicter()
  64. {
  65. sizeHistory = new int[4];
  66. for (int i = 0; i < sizeHistoryCount; i++)
  67. sizeHistory[i] = 256;
  68. }
  69. int PredictMessageSize()
  70. {
  71. int max = 0;
  72. for (int i = 0; i < sizeHistoryCount; i++)
  73. if (sizeHistory[i] > max)
  74. max = sizeHistory[i];
  75. return max + expectedSizeVariance;
  76. }
  77. void RecordActualMessageSize(int size)
  78. {
  79. sizeHistory[sizeHistoryIndex] = size;
  80. sizeHistoryIndex = (sizeHistoryIndex + 1) % sizeHistoryCount;
  81. }
  82. }
  83. }