2 // System.Web.Services.Protocols.WebServiceHelper.cs
5 // Lluis Sanchez Gual (lluis@ximian.com)
7 // Copyright (C) Ximian, Inc. 2003
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System
.Xml
.Schema
;
37 using System
.Xml
.Serialization
;
38 using System
.Web
.Services
.Description
;
40 namespace System
.Web
.Services
.Protocols
42 internal class WebServiceHelper
44 public const string SoapEnvelopeNamespace
= "http://schemas.xmlsoap.org/soap/envelope/";
45 public const string Soap12EnvelopeNamespace
= "http://www.w3.org/2003/05/soap-envelope";
46 public const string SoapEncodingNamespace
= "http://schemas.xmlsoap.org/soap/encoding/";
47 public const string Soap12EncodingNamespace
= "http://www.w3.org/2003/05/soap-encoding";
48 static readonly char [] trimChars
= { '"', '\'' }
;
49 static readonly bool prettyXml
;
51 static WebServiceHelper ()
53 string pxml
= Environment
.GetEnvironmentVariable ("MONO_WEBSERVICES_PRETTYXML");
54 prettyXml
= (pxml
!= null && pxml
!= "no");
57 public static XmlTextWriter
CreateXmlWriter (Stream s
)
59 // What a waste of UTF8encoders, but it has to be thread safe.
60 XmlTextWriter xtw
= new XmlTextWriter (s
, new UTF8Encoding (false));
63 xtw
.Formatting
= Formatting
.Indented
;
68 public static Encoding
GetContentEncoding (string cts
, out string content_type
)
72 if (cts
== null) cts
= "";
76 int idx
= cts
.IndexOf (';');
80 content_type
= cts
.Substring (0, idx
);
82 content_type
= content_type
.Trim ();
83 for (start
= idx
+ 1; idx
!= -1;)
85 idx
= cts
.IndexOf (';', start
);
88 body
= cts
.Substring (start
);
91 body
= cts
.Substring (start
, idx
- start
);
95 if (String
.CompareOrdinal (body
, 0, "charset=", 0, 8) == 0)
97 encoding
= body
.Substring (8);
98 encoding
= encoding
.TrimStart (trimChars
).TrimEnd (trimChars
);
102 return Encoding
.GetEncoding (encoding
);
105 public static string GetContextAction (string cts
) {
106 if (cts
== null || cts
.Length
== 0)
110 int idx
= cts
.IndexOf (';');
111 for (start
= idx
+ 1; idx
!= -1;)
113 idx
= cts
.IndexOf (';', start
);
116 body
= cts
.Substring (start
);
119 body
= cts
.Substring (start
, idx
- start
);
123 string actionEq
= "action=";
124 if (String
.CompareOrdinal(body
, 0, actionEq
, 0, actionEq
.Length
) == 0)
126 string action
= body
.Substring (actionEq
.Length
);
127 return action
.Trim (trimChars
);
135 public static void WriteSoapMessage (XmlTextWriter xtw
, SoapMethodStubInfo method
, SoapHeaderDirection dir
, object bodyContent
, SoapHeaderCollection headers
, bool soap12
)
137 SoapBindingUse methodUse
= dir
== SoapHeaderDirection
.Fault
? SoapBindingUse
.Literal
: method
.Use
;
138 XmlSerializer bodySerializer
= method
.GetBodySerializer (dir
, soap12
);
139 XmlSerializer headerSerializer
= method
.GetHeaderSerializer (dir
);
140 object[] headerArray
= method
.GetHeaderValueArray (dir
, headers
);
141 WriteSoapMessage (xtw
, methodUse
, bodySerializer
, headerSerializer
, bodyContent
, headerArray
, soap12
);
144 public static void WriteSoapMessage (XmlTextWriter xtw
, SoapBindingUse methodUse
, XmlSerializer bodySerializer
, XmlSerializer headerSerializer
, object bodyContent
, object[] headers
, bool soap12
)
147 WebServiceHelper
.Soap12EnvelopeNamespace
:
148 WebServiceHelper
.SoapEnvelopeNamespace
;
149 string encNS
= soap12
?
150 WebServiceHelper
.Soap12EncodingNamespace
:
151 WebServiceHelper
.SoapEncodingNamespace
;
152 xtw
.WriteStartDocument ();
153 xtw
.WriteStartElement ("soap", "Envelope", ns
);
154 xtw
.WriteAttributeString ("xmlns", "xsi", null, XmlSchema
.InstanceNamespace
);
155 xtw
.WriteAttributeString ("xmlns", "xsd", null, XmlSchema
.Namespace
);
160 xtw
.WriteStartElement ("soap", "Header", ns
);
161 headerSerializer
.Serialize (xtw
, headers
);
162 xtw
.WriteEndElement ();
166 xtw
.WriteStartElement ("soap", "Body", ns
);
168 if (methodUse
== SoapBindingUse
.Encoded
)
169 xtw
.WriteAttributeString ("encodingStyle", ns
, encNS
);
171 bodySerializer
.Serialize (xtw
, bodyContent
);
173 xtw
.WriteEndElement ();
174 xtw
.WriteEndElement ();
178 public static void ReadSoapMessage (XmlTextReader xmlReader
, SoapMethodStubInfo method
, SoapHeaderDirection dir
, bool soap12
, out object body
, out SoapHeaderCollection headers
)
180 XmlSerializer bodySerializer
= method
.GetBodySerializer (dir
, false);// no need to worry about soap12 arg since no call for Fault anyways here.
181 XmlSerializer headerSerializer
= method
.GetHeaderSerializer (dir
);
182 ReadSoapMessage (xmlReader
, bodySerializer
, headerSerializer
, soap12
, out body
, out headers
);
185 public static void ReadSoapMessage (XmlTextReader xmlReader
, XmlSerializer bodySerializer
, XmlSerializer headerSerializer
, bool soap12
, out object body
, out SoapHeaderCollection headers
)
187 xmlReader
.MoveToContent ();
188 string ns
= xmlReader
.NamespaceURI
;
191 case WebServiceHelper
.Soap12EnvelopeNamespace
:
193 case WebServiceHelper
.SoapEnvelopeNamespace
:
196 throw new SoapException (String
.Format ("SOAP version mismatch. Namespace '{0}' is not supported in this runtime profile.", ns
), VersionMismatchFaultCode (soap12
));
198 xmlReader
.ReadStartElement ("Envelope", ns
);
200 headers
= ReadHeaders (xmlReader
, headerSerializer
, ns
);
202 xmlReader
.MoveToContent ();
203 xmlReader
.ReadStartElement ("Body", ns
);
204 xmlReader
.MoveToContent ();
206 if (xmlReader
.LocalName
== "Fault" && xmlReader
.NamespaceURI
== ns
)
207 bodySerializer
= ns
== Soap12EnvelopeNamespace
? Soap12Fault
.Serializer
: Fault
.Serializer
;
209 body
= bodySerializer
.Deserialize (xmlReader
);
212 static SoapHeaderCollection
ReadHeaders (XmlTextReader xmlReader
, XmlSerializer headerSerializer
, string ns
)
214 SoapHeaderCollection headers
= null;
215 while (! (xmlReader
.NodeType
== XmlNodeType
.Element
&& xmlReader
.LocalName
== "Body" && xmlReader
.NamespaceURI
== ns
))
217 if (xmlReader
.NodeType
== XmlNodeType
.Element
&& xmlReader
.LocalName
== "Header"
218 && xmlReader
.NamespaceURI
== ns
&& !xmlReader
.IsEmptyElement
219 && headerSerializer
!= null)
221 xmlReader
.ReadStartElement ();
222 xmlReader
.MoveToContent ();
224 HeaderSerializationHelper uh
= new HeaderSerializationHelper (headerSerializer
);
225 headers
= uh
.Deserialize (xmlReader
);
227 while (xmlReader
.NodeType
!= XmlNodeType
.EndElement
)
230 xmlReader
.ReadEndElement ();
238 return new SoapHeaderCollection ();
241 class HeaderSerializationHelper
243 SoapHeaderCollection headers
;
244 XmlSerializer headerSerializer
;
246 public HeaderSerializationHelper (XmlSerializer headerSerializer
)
248 this.headers
= new SoapHeaderCollection ();
249 this.headerSerializer
= headerSerializer
;
252 public SoapHeaderCollection
Deserialize (XmlTextReader xmlReader
)
255 headerSerializer
.UnknownElement
+= new XmlElementEventHandler (OnAddUnknownHeader
);
256 object[] headerArray
= (object[]) headerSerializer
.Deserialize (xmlReader
);
257 foreach (SoapHeader h
in headerArray
)
258 if (h
!= null) headers
.Add (h
);
261 headerSerializer
.UnknownElement
-= new XmlElementEventHandler (OnAddUnknownHeader
);
265 void OnAddUnknownHeader (object sender
, XmlElementEventArgs e
)
267 headers
.Add (new SoapUnknownHeader (e
.Element
));
272 public static SoapException
Soap12FaultToSoapException (Soap12Fault fault
)
274 Soap12FaultReasonText text
=
275 fault
.Reason
!= null &&
276 fault
.Reason
.Texts
!= null &&
277 fault
.Reason
.Texts
.Length
> 0 ?
278 fault
.Reason
.Texts
[fault
.Reason
.Texts
.Length
- 1] : null;
279 XmlNode detail
= (fault
.Detail
== null) ? null :
280 (fault
.Detail
.Children
!= null &&
281 fault
.Detail
.Children
.Length
> 0) ?
282 (XmlNode
) fault
.Detail
.Children
[0] :
283 (fault
.Detail
.Attributes
!= null &&
284 fault
.Detail
.Attributes
.Length
> 0) ?
285 fault
.Detail
.Attributes
[0] : null;
286 SoapFaultSubCode subcode
= Soap12Fault
.GetSoapFaultSubCode (fault
.Code
.Subcode
);
287 return new SoapException (
288 text
!= null ? text
.Value
: null,
289 fault
.Code
.Value
, null, fault
.Role
,
290 text
!= null ? text
.XmlLang
: null,
291 detail
, subcode
, null);
295 public static XmlQualifiedName
ClientFaultCode (bool soap12
)
298 return soap12
? Soap12FaultCodes
.SenderFaultCode
: SoapException
.ClientFaultCode
;
300 return SoapException
.ClientFaultCode
;
304 public static XmlQualifiedName
ServerFaultCode (bool soap12
)
307 return soap12
? Soap12FaultCodes
.ReceiverFaultCode
: SoapException
.ServerFaultCode
;
309 return SoapException
.ServerFaultCode
;
313 public static XmlQualifiedName
MustUnderstandFaultCode (bool soap12
)
316 return soap12
? Soap12FaultCodes
.ReceiverFaultCode
: SoapException
.MustUnderstandFaultCode
;
318 return SoapException
.MustUnderstandFaultCode
;
322 public static XmlQualifiedName
VersionMismatchFaultCode (bool soap12
)
325 return soap12
? Soap12FaultCodes
.VersionMismatchFaultCode
: SoapException
.VersionMismatchFaultCode
;
327 return SoapException
.VersionMismatchFaultCode
;
331 public static void InvalidOperation (string message
, WebResponse response
, Encoding enc
)
333 if (response
== null)
334 throw new InvalidOperationException (message
);
339 StringBuilder sb
= new StringBuilder ();
341 if (response
.ContentLength
> 0) {
342 sb
.Append ("\r\nResponse error message:\r\n--\r\n");
345 StreamReader resp
= new StreamReader (response
.GetResponseStream (), enc
);
346 sb
.Append (resp
.ReadToEnd ());
347 } catch (Exception
) {
351 throw new InvalidOperationException (sb
.ToString ());