// // Message.cs // // Author: // Atsushi Enomoto // // Copyright (C) 2005-2006,2010 Novell, Inc. http://www.novell.com // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections.Generic; using System.IO; using System.Runtime.Serialization; using System.Xml; using System.Xml.Schema; using Mono.Xml.XPath; namespace System.ServiceModel.Channels { public abstract class Message : IDisposable { bool disposed; string body_id; protected Message () { State = MessageState.Created; } public abstract MessageHeaders Headers { get; } public virtual bool IsEmpty { get { return false; } } public virtual bool IsFault { get { return false; } } public abstract MessageProperties Properties { get; } MessageState ___state; public MessageState State { get { return ___state; } private set { ___state = value; } } public abstract MessageVersion Version { get; } protected bool IsDisposed { get { return disposed; } } public void Close () { if (!disposed) OnClose (); State = MessageState.Closed; disposed = true; } public MessageBuffer CreateBufferedCopy (int maxBufferSize) { if (State != MessageState.Created) throw new InvalidOperationException (String.Format ("The message is already at {0} state", State)); try { return OnCreateBufferedCopy (maxBufferSize); } finally { State = MessageState.Copied; } } void IDisposable.Dispose () { Close (); } public T GetBody () { return GetBody (new DataContractSerializer (typeof (T))); } public T GetBody (XmlObjectSerializer xmlFormatter) { return (T) xmlFormatter.ReadObject (GetReaderAtBodyContents ()); } public string GetBodyAttribute (string localName, string ns) { return OnGetBodyAttribute (localName, ns); } public XmlDictionaryReader GetReaderAtBodyContents () { return OnGetReaderAtBodyContents (); } public override string ToString () { MessageState tempState = State; try { StringWriter sw = new StringWriter (); XmlWriterSettings settings = new XmlWriterSettings (); settings.Indent = true; settings.OmitXmlDeclaration = true; using (XmlWriter w = XmlWriter.Create (sw, settings)) { WriteMessage (w); } return sw.ToString (); } finally { State = tempState; } } void WriteXsiNil (XmlDictionaryWriter writer) { var dic = Constants.SoapDictionary; writer.WriteStartElement ("z", dic.Add ("anyType"), dic.Add (Constants.MSSerialization)); writer.WriteAttributeString ("i", dic.Add ("nil"), dic.Add ("http://www.w3.org/2001/XMLSchema-instance"), "true"); writer.WriteEndElement (); } public void WriteBody (XmlDictionaryWriter writer) { if (Version.Envelope != EnvelopeVersion.None) WriteStartBody (writer); WriteBodyContents (writer); if (Version.Envelope != EnvelopeVersion.None) writer.WriteEndElement (); } public void WriteBody (XmlWriter writer) { WriteBody (XmlDictionaryWriter.CreateDictionaryWriter (writer)); } public void WriteBodyContents (XmlDictionaryWriter writer) { if (!IsEmpty) OnWriteBodyContents (writer); else if (Version.Envelope == EnvelopeVersion.None) WriteXsiNil (writer); State = MessageState.Written; } public void WriteMessage (XmlDictionaryWriter writer) { if (State != MessageState.Created) throw new InvalidOperationException (String.Format ("The message is already at {0} state", State)); OnWriteMessage (writer); } public void WriteMessage (XmlWriter writer) { WriteMessage (XmlDictionaryWriter.CreateDictionaryWriter (writer)); } public void WriteStartBody (XmlDictionaryWriter writer) { if (State != MessageState.Created) throw new InvalidOperationException (String.Format ("The message is already at {0} state", State)); OnWriteStartBody (writer); } public void WriteStartBody (XmlWriter writer) { WriteStartBody ( XmlDictionaryWriter.CreateDictionaryWriter (writer)); } public void WriteStartEnvelope (XmlDictionaryWriter writer) { if (State != MessageState.Created) throw new InvalidOperationException (String.Format ("The message is already at {0} state", State)); OnWriteStartEnvelope (writer); } [MonoTODO] protected virtual void OnBodyToString ( XmlDictionaryWriter writer) { throw new NotImplementedException (); } protected virtual void OnClose () { } protected virtual MessageBuffer OnCreateBufferedCopy ( int maxBufferSize) { var s = new XmlWriterSettings (); s.OmitXmlDeclaration = true; s.ConformanceLevel = ConformanceLevel.Auto; StringWriter sw = new StringWriter (); using (XmlDictionaryWriter w = XmlDictionaryWriter.CreateDictionaryWriter (XmlWriter.Create (sw, s))) WriteBodyContents (w); var headers = new MessageHeaders (Headers); var props = new MessageProperties (Properties); return new DefaultMessageBuffer (maxBufferSize, headers, props, new XmlReaderBodyWriter (sw.ToString (), maxBufferSize, null), false, new AttributeCollection ()); } protected virtual string OnGetBodyAttribute ( string localName, string ns) { return null; } protected virtual XmlDictionaryReader OnGetReaderAtBodyContents () { var ws = new XmlWriterSettings (); ws.ConformanceLevel = ConformanceLevel.Auto; StringWriter sw = new StringWriter (); using (XmlDictionaryWriter body = XmlDictionaryWriter.CreateDictionaryWriter (XmlWriter.Create (sw, ws))) { WriteBodyContents (body); } var rs = new XmlReaderSettings (); rs.ConformanceLevel = ConformanceLevel.Auto; return XmlDictionaryReader.CreateDictionaryReader (XmlReader.Create (new StringReader (sw.ToString ()), rs)); } protected abstract void OnWriteBodyContents ( XmlDictionaryWriter writer); protected virtual void OnWriteMessage ( XmlDictionaryWriter writer) { if (Version.Envelope != EnvelopeVersion.None) { WriteStartEnvelope (writer); if (Headers.Count > 0) { OnWriteStartHeaders (writer); for (int i = 0, count = Headers.Count; i < count; i++) Headers.WriteHeader (i, writer); writer.WriteEndElement (); } } WriteBody (writer); if (Version.Envelope != EnvelopeVersion.None) writer.WriteEndElement (); } protected virtual void OnWriteStartBody ( XmlDictionaryWriter writer) { var dic = Constants.SoapDictionary; writer.WriteStartElement ("s", dic.Add ("Body"), dic.Add (Version.Envelope.Namespace)); } protected virtual void OnWriteStartEnvelope ( XmlDictionaryWriter writer) { var dic = Constants.SoapDictionary; writer.WriteStartElement ("s", dic.Add ("Envelope"), dic.Add (Version.Envelope.Namespace)); if (Headers.Action != null && Version.Addressing.Namespace != MessageVersion.None.Addressing.Namespace) writer.WriteXmlnsAttribute ("a", dic.Add (Version.Addressing.Namespace)); foreach (MessageHeaderInfo h in Headers) if (h.Id != null && writer.LookupPrefix (Constants.WsuNamespace) != "u") { writer.WriteXmlnsAttribute ("u", dic.Add (Constants.WsuNamespace)); break; } } protected virtual void OnWriteStartHeaders ( XmlDictionaryWriter writer) { var dic = Constants.SoapDictionary; writer.WriteStartElement ("s", dic.Add ("Header"), dic.Add (Version.Envelope.Namespace)); } #region factory methods // 1) version, code, reason, action -> 3 // 2) version, code, reason, detail, action -> 3 // 3) version, fault, action -> SimpleMessage // 4) version, action, body -> 10 or 5 // 5) version, action, body, formatter -> 10 or 9 // 6) version, action, xmlReader -> 7 // 7) version, action, reader -> 9 // 8) xmlReader, maxSizeOfHeaders, version -> 11 // 9) version, action, body -> SimpleMessage // 10) version, action -> EmptyMessage // 11) reader, maxSizeOfHeaders, version -> XmlReaderMessage // 1) public static Message CreateMessage (MessageVersion version, FaultCode code, string reason, string action) { MessageFault fault = MessageFault.CreateFault (code, reason); return CreateMessage (version, fault, action); } // 2) public static Message CreateMessage (MessageVersion version, FaultCode code, string reason, object detail, string action) { MessageFault fault = MessageFault.CreateFault ( code, new FaultReason (reason), detail); return CreateMessage (version, fault, action); } // 3) public static Message CreateMessage (MessageVersion version, MessageFault fault, string action) { return new SimpleMessage (version, action, new MessageFaultBodyWriter (fault, version), true, empty_attributes); } // 4) public static Message CreateMessage (MessageVersion version, string action, object body) { return body == null ? CreateMessage (version, action) : CreateMessage (version, action, body, new DataContractSerializer (body.GetType ())); } // 5) public static Message CreateMessage (MessageVersion version, string action, object body, XmlObjectSerializer xmlFormatter) { return body == null ? CreateMessage (version, action) : CreateMessage ( version, action, new XmlObjectSerializerBodyWriter (body, xmlFormatter)); } // 6) public static Message CreateMessage (MessageVersion version, string action, XmlReader body) { return CreateMessage (version, action, XmlDictionaryReader.CreateDictionaryReader (body)); } // 7) public static Message CreateMessage (MessageVersion version, string action, XmlDictionaryReader body) { return CreateMessage (version, action, new XmlReaderBodyWriter (body)); } // 8) public static Message CreateMessage (XmlReader envelopeReader, int maxSizeOfHeaders, MessageVersion version) { return CreateMessage ( XmlDictionaryReader.CreateDictionaryReader (envelopeReader), maxSizeOfHeaders, version); } // Core implementations of CreateMessage. static readonly AttributeCollection empty_attributes = new AttributeCollection (); // 9) public static Message CreateMessage (MessageVersion version, string action, BodyWriter body) { if (version == null) throw new ArgumentNullException ("version"); if (body == null) throw new ArgumentNullException ("body"); return new SimpleMessage (version, action, body, false, empty_attributes); } // 10) public static Message CreateMessage (MessageVersion version, string action) { if (version == null) throw new ArgumentNullException ("version"); return new EmptyMessage (version, action); } // 11) public static Message CreateMessage ( XmlDictionaryReader envelopeReader, int maxSizeOfHeaders, MessageVersion version) { if (envelopeReader == null) throw new ArgumentNullException ("envelopeReader"); if (version == null) throw new ArgumentNullException ("version"); return new XmlReaderMessage (version, envelopeReader, maxSizeOfHeaders); } #endregion } }