| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430 |
- //
- // MessageFault.cs
- //
- // Author:
- // Atsushi Enomoto <[email protected]>
- //
- // Copyright (C) 2005-2006 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;
- namespace System.ServiceModel.Channels
- {
- public abstract class MessageFault
- {
- // type members
- public static MessageFault CreateFault (Message message, int maxBufferSize)
- {
- if (message.Version.Envelope == EnvelopeVersion.Soap11)
- return CreateFault11 (message, maxBufferSize);
- else if (message.Version.Envelope == EnvelopeVersion.Soap12)
- return CreateFault12 (message, maxBufferSize);
- throw new InvalidOperationException ("The input message is not a SOAP envelope.");
- }
- static MessageFault CreateFault11 (Message message, int maxBufferSize)
- {
- FaultCode fc = null;
- FaultReason fr = null;
- object details = null;
- XmlDictionaryReader r = message.GetReaderAtBodyContents ();
- r.ReadStartElement ("Fault", message.Version.Envelope.Namespace);
- r.MoveToContent ();
- while (r.NodeType != XmlNodeType.EndElement) {
- switch (r.LocalName) {
- case "faultcode":
- fc = ReadFaultCode11 (r);
- break;
- case "faultstring":
- fr = new FaultReason (r.ReadElementContentAsString());
- break;
- case "detail":
- //BUGBUG: Handle children of type other than ExceptionDetail, in order to comply with
- // FaultContractAttribute.
- r.ReadStartElement ();
- r.MoveToContent();
- details = new DataContractSerializer (typeof (ExceptionDetail)).ReadObject (r);
- break;
- case "faultactor":
- default:
- throw new NotImplementedException ();
- }
- r.MoveToContent ();
- }
- r.ReadEndElement ();
- if (details == null)
- return CreateFault (fc, fr);
- return CreateFault (fc, fr, details);
- }
- static MessageFault CreateFault12 (Message message, int maxBufferSize)
- {
- FaultCode fc = null;
- FaultReason fr = null;
- XmlDictionaryReader r = message.GetReaderAtBodyContents ();
- r.ReadStartElement ("Fault", message.Version.Envelope.Namespace);
- r.MoveToContent ();
- while (r.NodeType != XmlNodeType.EndElement) {
- switch (r.LocalName) {
- case "Code":
- fc = ReadFaultCode12 (r, message.Version.Envelope.Namespace);
- break;
- case "Reason":
- fr = ReadFaultReason12 (r, message.Version.Envelope.Namespace);
- break;
- default:
- throw new NotImplementedException ();
- }
- }
- r.ReadEndElement ();
- return CreateFault (fc, fr);
- }
- static FaultCode ReadFaultCode11 (XmlDictionaryReader r)
- {
- FaultCode subcode = null;
- XmlQualifiedName value = XmlQualifiedName.Empty;
- if (r.IsEmptyElement)
- throw new ArgumentException ("Fault Code is mandatory in SOAP fault message.");
- r.ReadStartElement ("faultcode");
- r.MoveToContent ();
- while (r.NodeType != XmlNodeType.EndElement) {
- if (r.NodeType == XmlNodeType.Element)
- subcode = ReadFaultCode11 (r);
- else
- value = (XmlQualifiedName) r.ReadContentAs (typeof (XmlQualifiedName), r as IXmlNamespaceResolver);
- r.MoveToContent ();
- }
- r.ReadEndElement ();
- return new FaultCode (value.Name, value.Namespace, subcode);
- }
- static FaultCode ReadFaultCode12 (XmlDictionaryReader r, string ns)
- {
- FaultCode subcode = null;
- XmlQualifiedName value = XmlQualifiedName.Empty;
- if (r.IsEmptyElement)
- throw new ArgumentException ("Value element is mandatory in SOAP fault code.");
- r.ReadStartElement ("Code", ns);
- r.MoveToContent ();
- while (r.NodeType != XmlNodeType.EndElement) {
- switch (r.LocalName) {
- case "Subcode":
- subcode = ReadFaultCode12 (r, ns);
- break;
- case "Value":
- value = (XmlQualifiedName) r.ReadElementContentAs (typeof (XmlQualifiedName), r as IXmlNamespaceResolver, "Value", ns);
- break;
- default:
- throw new ArgumentException ();
- }
- r.MoveToContent ();
- }
- r.ReadEndElement ();
- return new FaultCode (value.Name, value.Namespace, subcode);
- }
- static FaultReason ReadFaultReason12 (XmlDictionaryReader r, string ns)
- {
- List<FaultReasonText> l = new List<FaultReasonText> ();
- if (r.IsEmptyElement)
- throw new ArgumentException ("One or more Text element is mandatory in SOAP fault reason text.");
- r.ReadStartElement ("Code", ns);
- for (r.MoveToContent ();
- r.NodeType != XmlNodeType.EndElement;
- r.MoveToContent ()) {
- string lang = r.GetAttribute ("lang", "http://www.w3.org/XML/1998/namespace");
- l.Add (new FaultReasonText (r.ReadElementContentAsString ("Text", ns), lang));
- }
- return new FaultReason (l);
- }
- public static MessageFault CreateFault (FaultCode code,
- string reason)
- {
- return CreateFault (code, new FaultReason (reason));
- }
- public static MessageFault CreateFault (FaultCode code,
- FaultReason reason)
- {
- return new SimpleMessageFault (code, reason,
- false, null, null, null, null);
- }
- public static MessageFault CreateFault (FaultCode code,
- FaultReason reason, object detail)
- {
- return new SimpleMessageFault (code, reason,
- true, detail, new DataContractSerializer (detail.GetType ()), null, null);
- }
- public static MessageFault CreateFault (FaultCode code,
- FaultReason reason, object detail,
- XmlObjectSerializer formatter)
- {
- return new SimpleMessageFault (code, reason, true,
- detail, formatter, String.Empty, String.Empty);
- }
- public static MessageFault CreateFault (FaultCode code,
- FaultReason reason, object detail,
- XmlObjectSerializer formatter, string actor)
- {
- return new SimpleMessageFault (code, reason,
- true, detail, formatter, actor, String.Empty);
- }
- public static MessageFault CreateFault (FaultCode code,
- FaultReason reason, object detail,
- XmlObjectSerializer formatter, string actor, string node)
- {
- return new SimpleMessageFault (code, reason,
- true, detail, formatter, actor, node);
- }
- // pretty simple implementation class
- internal class SimpleMessageFault : MessageFault
- {
- bool has_detail;
- string actor, node;
- FaultCode code;
- FaultReason reason;
- object detail;
- XmlObjectSerializer formatter;
- public SimpleMessageFault (FaultCode code,
- FaultReason reason, bool has_detail,
- object detail, XmlObjectSerializer formatter,
- string actor, string node)
- : this (code, reason, detail, formatter, actor, node)
- {
- this.has_detail = has_detail;
- }
- public SimpleMessageFault (FaultCode code,
- FaultReason reason,
- object detail, XmlObjectSerializer formatter,
- string actor, string node)
- {
- if (code == null)
- throw new ArgumentNullException ("code");
- if (reason == null)
- throw new ArgumentNullException ("reason");
- this.code = code;
- this.reason = reason;
- this.detail = detail;
- this.formatter = formatter;
- this.actor = actor;
- this.node = node;
- }
- public override string Actor {
- get { return actor; }
- }
- public override FaultCode Code {
- get { return code; }
- }
- public override bool HasDetail {
- // it is not simply "detail != null" since
- // null detail could become <ms:anyType xsi:nil="true" />
- get { return has_detail; }
- }
- public override string Node {
- get { return node; }
- }
- public override FaultReason Reason {
- get { return reason; }
- }
- protected override XmlDictionaryReader OnGetReaderAtDetailContents ()
- {
- // FIXME: use XmlObjectSerializer
- return base.OnGetReaderAtDetailContents ();
- }
- protected override void OnWriteDetailContents (XmlDictionaryWriter writer)
- {
- formatter.WriteObject (writer, detail);
- }
- public object Detail {
- get { return detail; }
- }
- }
- // instance members
- protected MessageFault ()
- {
- }
- [MonoTODO ("is this true?")]
- public virtual string Actor {
- get { return String.Empty; }
- }
- public abstract FaultCode Code { get; }
- public abstract bool HasDetail { get; }
- [MonoTODO ("is this true?")]
- public virtual string Node {
- get { return String.Empty; }
- }
- public abstract FaultReason Reason { get; }
- public T GetDetail<T> ()
- {
- return GetDetail<T> (new DataContractSerializer (typeof (T)));
- }
- public T GetDetail<T> (XmlObjectSerializer formatter)
- {
- if (!HasDetail)
- throw new InvalidOperationException ("This message does not have details.");
- return (T) formatter.ReadObject (GetReaderAtDetailContents ());
- }
- public XmlDictionaryReader GetReaderAtDetailContents ()
- {
- return OnGetReaderAtDetailContents ();
- }
- public void WriteTo (XmlDictionaryWriter writer,
- EnvelopeVersion version)
- {
- writer.WriteStartElement ("Fault", version.Namespace);
- WriteFaultCode (writer, version, Code);
- WriteReason (writer, version);
- if (HasDetail)
- OnWriteDetail (writer, version);
- writer.WriteEndElement ();
- }
- private void WriteFaultCode (XmlDictionaryWriter writer,
- EnvelopeVersion version, FaultCode code)
- {
- if (version == EnvelopeVersion.Soap11) {
- writer.WriteStartElement ("", "faultcode", version.Namespace);
- if (code.Namespace.Length > 0)
- writer.WriteXmlnsAttribute ("a", code.Namespace);
- writer.WriteQualifiedName (code.Name, code.Namespace);
- writer.WriteEndElement ();
- } else { // Soap12
- writer.WriteStartElement ("Code", version.Namespace);
- writer.WriteStartElement ("Value", version.Namespace);
- if (code.Namespace.Length > 0)
- writer.WriteXmlnsAttribute ("a", code.Namespace);
- writer.WriteQualifiedName (code.Name, code.Namespace);
- if (code.SubCode != null)
- WriteFaultCode (writer, version, code.SubCode);
- writer.WriteEndElement ();
- writer.WriteEndElement ();
- }
- }
- private void WriteReason (XmlDictionaryWriter writer,
- EnvelopeVersion version)
- {
- if (version == EnvelopeVersion.Soap11) {
- foreach (FaultReasonText t in Reason.Translations) {
- writer.WriteStartElement ("", "faultstring", version.Namespace);
- if (t.XmlLang != null)
- writer.WriteAttributeString ("xml", "lang", null, t.XmlLang);
- writer.WriteString (t.Text);
- writer.WriteEndElement ();
- }
- } else { // Soap12
- writer.WriteStartElement ("Reason", version.Namespace);
- foreach (FaultReasonText t in Reason.Translations) {
- writer.WriteStartElement ("Text", version.Namespace);
- if (t.XmlLang != null)
- writer.WriteAttributeString ("xml", "lang", null, t.XmlLang);
- writer.WriteString (t.Text);
- writer.WriteEndElement ();
- }
- writer.WriteEndElement ();
- }
- }
- public void WriteTo (XmlWriter writer, EnvelopeVersion version)
- {
- WriteTo (XmlDictionaryWriter.CreateDictionaryWriter (
- writer), version);
- }
- protected virtual XmlDictionaryReader OnGetReaderAtDetailContents ()
- {
- MemoryStream ms = new MemoryStream ();
- using (XmlDictionaryWriter dw =
- XmlDictionaryWriter.CreateDictionaryWriter (
- XmlWriter.Create (ms))) {
- OnWriteDetailContents (dw);
- }
- ms.Seek (0, SeekOrigin.Begin);
- return XmlDictionaryReader.CreateDictionaryReader (
- XmlReader.Create (ms));
- }
- protected virtual void OnWriteDetail (XmlDictionaryWriter writer, EnvelopeVersion version)
- {
- OnWriteStartDetail (writer, version);
- OnWriteDetailContents (writer);
- writer.WriteEndElement ();
- }
- protected virtual void OnWriteStartDetail (XmlDictionaryWriter writer, EnvelopeVersion version)
- {
- if (version == EnvelopeVersion.Soap11)
- writer.WriteStartElement ("detail", String.Empty);
- else // Soap12
- writer.WriteStartElement ("Detail", version.Namespace);
- }
- protected abstract void OnWriteDetailContents (XmlDictionaryWriter writer);
- }
- }
|