处置 XmlWriter 而不发送未完成的结束元素
Posted
技术标签:
【中文标题】处置 XmlWriter 而不发送未完成的结束元素【英文标题】:Dispose of an XmlWriter without sending outstanding end elements 【发布时间】:2010-11-17 11:17:33 【问题描述】:我正在使用XmlWriter
发送 XMPP (Jingle) 流。 XMPP 协议在协商 TLS 时替换了 XML 流,这意味着 XML 最终如下:
<stream>
<features>
...
</features>
...TLS gets negotiated...
<stream>
...
</stream>
XML 最终格式不正确,因为有两个流开始标记。
我想要做的是扔掉我在 TLS 协商之前使用的 XmlWriter
并创建一个全新的,它可以让我更好地模块化我的代码。但是,当我调用 myXmlWriter.Close()
以确保它被处理时,它将发送打破 XMPP 协议的关闭流结束元素。
无论如何我可以关闭XmlWriter
而不发送未完成的结束元素吗?
【问题讨论】:
【参考方案1】:创建一个中间流,您可以使用它来断开 XmlWriter 与基本流的连接。
这不是最优雅的解决方案,下面的代码需要工作,所以在将其投入生产之前对其进行测试,但这是关于想法的。
public class DummyStream : Stream
public DummyStream(Stream baseStream)
if (baseStream == null)
throw new ArgumentNullException("baseStream");
BaseStream = baseStream;
public Stream BaseStream get; private set;
public void DisconnectBaseStream()
BaseStream = null;
private Stream GetBaseStream()
return BaseStream ?? Stream.Null;
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
return GetBaseStream().BeginRead(buffer, offset, count, callback, state);
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
return GetBaseStream().BeginWrite(buffer, offset, count, callback, state);
public override bool CanRead
get return GetBaseStream().CanRead;
public override bool CanSeek
get return GetBaseStream().CanSeek;
public override bool CanTimeout
get return GetBaseStream().CanTimeout;
public override bool CanWrite
get return GetBaseStream().CanWrite;
public override void Close()
// We do not close the BaseStream because this stream
// is just a wrapper.
// GetBaseStream().Close();
public override ObjRef CreateObjRef(Type requestedType)
return GetBaseStream().CreateObjRef(requestedType);
protected override void Dispose(bool disposing)
base.Dispose(disposing);
// We do not dispose the BaseStream because this stream
// is just a wrapper.
public override int EndRead(IAsyncResult asyncResult)
return GetBaseStream().EndRead(asyncResult);
public override void EndWrite(IAsyncResult asyncResult)
GetBaseStream().EndWrite(asyncResult);
public override bool Equals(object obj)
return GetBaseStream().Equals(obj);
public override void Flush()
GetBaseStream().Flush();
public override int GetHashCode()
return GetBaseStream().GetHashCode();
public override object InitializeLifetimeService()
return GetBaseStream().InitializeLifetimeService();
public override long Length
get return GetBaseStream().Length;
public override long Position
get return GetBaseStream().Position;
set GetBaseStream().Position = value;
public override int Read(byte[] buffer, int offset, int count)
return GetBaseStream().Read(buffer, offset, count);
public override int ReadByte()
return GetBaseStream().ReadByte();
public override int ReadTimeout
get return GetBaseStream().ReadTimeout;
set GetBaseStream().ReadTimeout = value;
public override long Seek(long offset, SeekOrigin origin)
return GetBaseStream().Seek(offset, origin);
public override void SetLength(long value)
GetBaseStream().SetLength(value);
public override string ToString()
return GetBaseStream().ToString();
public override void Write(byte[] buffer, int offset, int count)
GetBaseStream().Write(buffer, offset, count);
public override void WriteByte(byte value)
GetBaseStream().WriteByte(value);
public override int WriteTimeout
get return GetBaseStream().WriteTimeout;
set GetBaseStream().WriteTimeout = value;
此类旨在用作XmlWriter
和XmlWriter
输出到的流之间的流。这个类只是将所有来自XmlWriter
的调用转发到基本流,但是一旦你调用DisconnectBaseStream
,它就会停止转发它们并且XmlWriter
不能再控制基本流。
你可以像这样使用这个类:
using (var stream = /* stream used to communicate with */)
using (var wrapperStream = new DummyStream(stream))
using (var writer = XmlWriter.Create(wrapperStream))
// Do you work here.
// Now, disconnect the dummy stream so that the XML writer
// cannot send more data.
wrapperStream.DisconnectBaseStream();
// End of the using block will close the XmlWriter and it
// cannot send more data to the base stream.
// Perform TLS negotiation etc...
同样,DummyStream
是一个起点,需要一些工作。例如,您需要确保XmlWriter
在断开连接后不会拨打电话,这将导致崩溃,因此您需要进行一些检查,例如Write
方法是否 BaseStream
是 null
如果是,则跳过调用。
【讨论】:
我其实也想过这样做。我过去使用过自定义 Stream 类。我只是希望有一些不那么笨重的东西,哦。 无论您做什么,XmlWriter
都会尽力输出格式良好的 XML。这是解决这个问题的唯一方法。以上是关于处置 XmlWriter 而不发送未完成的结束元素的主要内容,如果未能解决你的问题,请参考以下文章
在 XElement WriteTo 方法中,强制 XmlWriter 为具有已定义 xmlns 属性的子元素使用前缀