//------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ namespace System.ServiceModel.Channels { using System.Xml; using System.Diagnostics; using System.Runtime; using System.Threading; public abstract class BodyWriter { bool isBuffered; bool canWrite; object thisLock; protected BodyWriter(bool isBuffered) { this.isBuffered = isBuffered; this.canWrite = true; if (!this.isBuffered) { this.thisLock = new object(); } } public bool IsBuffered { get { return this.isBuffered; } } internal virtual bool IsEmpty { get { return false; } } internal virtual bool IsFault { get { return false; } } public BodyWriter CreateBufferedCopy(int maxBufferSize) { if (maxBufferSize < 0) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("maxBufferSize", maxBufferSize, SR.GetString(SR.ValueMustBeNonNegative))); if (this.isBuffered) { return this; } else { lock (this.thisLock) { if (!this.canWrite) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.BodyWriterCanOnlyBeWrittenOnce))); this.canWrite = false; } BodyWriter bodyWriter = OnCreateBufferedCopy(maxBufferSize); if (!bodyWriter.IsBuffered) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.BodyWriterReturnedIsNotBuffered))); return bodyWriter; } } protected virtual BodyWriter OnCreateBufferedCopy(int maxBufferSize) { return OnCreateBufferedCopy(maxBufferSize, XmlDictionaryReaderQuotas.Max); } internal BodyWriter OnCreateBufferedCopy(int maxBufferSize, XmlDictionaryReaderQuotas quotas) { XmlBuffer buffer = new XmlBuffer(maxBufferSize); using (XmlDictionaryWriter writer = buffer.OpenSection(quotas)) { writer.WriteStartElement("a"); OnWriteBodyContents(writer); writer.WriteEndElement(); } buffer.CloseSection(); buffer.Close(); return new BufferedBodyWriter(buffer); } protected abstract void OnWriteBodyContents(XmlDictionaryWriter writer); protected virtual IAsyncResult OnBeginWriteBodyContents(XmlDictionaryWriter writer, AsyncCallback callback, object state) { return new OnWriteBodyContentsAsyncResult(writer, this, callback, state); } protected virtual void OnEndWriteBodyContents(IAsyncResult result) { OnWriteBodyContentsAsyncResult.End(result); } void EnsureWriteBodyContentsState(XmlDictionaryWriter writer) { if (writer == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("writer")); if (!this.isBuffered) { lock (this.thisLock) { if (!this.canWrite) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.BodyWriterCanOnlyBeWrittenOnce))); this.canWrite = false; } } } public void WriteBodyContents(XmlDictionaryWriter writer) { EnsureWriteBodyContentsState(writer); OnWriteBodyContents(writer); } public IAsyncResult BeginWriteBodyContents(XmlDictionaryWriter writer, AsyncCallback callback, object state) { EnsureWriteBodyContentsState(writer); return OnBeginWriteBodyContents(writer, callback, state); } public void EndWriteBodyContents(IAsyncResult result) { OnEndWriteBodyContents(result); } class BufferedBodyWriter : BodyWriter { XmlBuffer buffer; public BufferedBodyWriter(XmlBuffer buffer) : base(true) { this.buffer = buffer; } protected override void OnWriteBodyContents(XmlDictionaryWriter writer) { XmlDictionaryReader reader = this.buffer.GetReader(0); using (reader) { reader.ReadStartElement(); while (reader.NodeType != XmlNodeType.EndElement) { writer.WriteNode(reader, false); } reader.ReadEndElement(); } } } class OnWriteBodyContentsAsyncResult : ScheduleActionItemAsyncResult { BodyWriter bodyWriter; XmlDictionaryWriter writer; public OnWriteBodyContentsAsyncResult(XmlDictionaryWriter writer, BodyWriter bodyWriter, AsyncCallback callback, object state) : base(callback, state) { Fx.Assert(bodyWriter != null, "bodyWriter should never be null"); this.writer = writer; this.bodyWriter = bodyWriter; Schedule(); } protected override void OnDoWork() { this.bodyWriter.OnWriteBodyContents(this.writer); } } } }