class XmlWriterBackedStream 与 KB2901983 的重大变化

Breaking change in class XmlWriterBackedStream with KB2901983

我有一个针对 .NET Framework 4.0 的应用程序,昨天我们的客户进行了某种更新,我们的应用程序停止工作。在深入研究 .NET Framework 源代码后,我在 XmlWriterBackedStream class 中找到了原因。我机器上的代码如下:


// C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ServiceModel.Web\v4.0_4.0.0.0__31bf3856ad364e35\System.ServiceModel.Web.dll
// System.ServiceModel.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35

// Architecture: AnyCPU (64-bit preferred)
// Runtime: .NET 4.0

// System.ServiceModel.Channels.StreamBodyWriter.XmlWriterBackedStream
public override void Write(byte[] buffer, int offset, int count)
{
    if (this.writer.WriteState == WriteState.Start)
    {
        this.writer.WriteStartElement("Binary", string.Empty);
        this.writer.WriteBase64(buffer, offset, count);
        return;
    }
    if (this.writer.WriteState == WriteState.Content)
    {
        this.writer.WriteBase64(buffer, offset, count);
    }
}

而客户机器上的 .NET 4.0 Framework 代码如下所示:


// C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.ServiceModel.Web\v4.0_4.0.0.0__31bf3856ad364e35\System.ServiceModel.Web.dll
// System.ServiceModel.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35

// Architecture: AnyCPU (64-bit preferred)
// Runtime: .NET 4.0

// System.ServiceModel.Channels.StreamBodyWriter.XmlWriterBackedStream
public override void Write(byte[] buffer, int offset, int count)
{
    if (this.writer.WriteState == WriteState.Content || this.isQuirkedTo40Behavior)
    {
        this.writer.WriteBase64(buffer, offset, count);
        return;
    }
    if (this.writer.WriteState == WriteState.Start)
    {
        this.writer.WriteStartElement("Binary", string.Empty);
        this.writer.WriteBase64(buffer, offset, count);
    }
}

注意客户机器上的 this.isQuirkedTo40Behavior。这迫使我针对 .NET Framework 4.5 编译应用程序以使其再次运行。

这是 .NET Framework 中的错误吗?如何在不针对 4.5 框架的情况下让我的应用程序再次运行?

这是我的 class 引起的问题:


class MyMessageWriter : StreamBodyWriter
{
   private readonly Action<System.IO.Stream> writerAction;

   public MyMessageWriter(Action<System.IO.Stream> writer) : base(false)
   {
      this.writerAction = writer;
   }

   protected override void OnWriteBodyContents(System.IO.Stream stream)
   {
      this.writerAction(stream);
   }
}

这似乎是安装 KB2901983(感谢 Microsoft!)带来的真正重大变化。但是我找到了解决此问题的方法,因此您仍然可以将您的应用程序定位到 .NET Framework 4.0(有点难看 - 但它有效):


class MyMessageWriter : StreamBodyWriter
{
   private readonly Action<System.IO.Stream> writerAction;

   public MyMessageWriter(Action<System.IO.Stream> writer) : base(false)
   {
      this.writerAction = writer;
   }

   protected override void OnWriteBodyContents(System.IO.Stream stream)
   {
      this.writerAction(stream);
   }

   protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
   {
      writer.WriteStartElement("Binary", string.Empty);
      writer.WriteBase64(new byte[0], 0, 0); // force WriteState.Content

      base.OnWriteBodyContents(writer);
   }
}

更新

如果您没有安装 KB2901983,此解决方案似乎不起作用。

更新 2

我不得不添加 writer.WriteBase64(new byte[0], 0, 0) 以强制 XmlDictionaryWriter 的状态为 WriteState.Content 现在它应该在安装 KB2901983 之前和之后工作

更新 3

另一种解决方案是将 XmlDictionaryWriter 包装到您自己的 Stream 派生中 class