2010-06-21 Marek Habersack <mhabersack@novell.com>
[mcs.git] / class / System.Web.Services / System.Web.Services.Protocols / SoapHttpClientProtocol.cs
blob61d54ca4df7b4e81e6a86d0bf698b07accdbf5ab
1 //
2 // System.Web.Services.Protocols.SoapHttpClientProtocol.cs
3 //
4 // Author:
5 // Tim Coleman (tim@timcoleman.com)
6 // Miguel de Icaza (miguel@ximian.com)
7 // Lluis Sanchez Gual (lluis@ximian.com)
8 //
9 // Copyright (C) Tim Coleman, 2002
10 // Copyright (C) Ximian, Inc, 2003
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.ComponentModel;
35 using System.Globalization;
36 using System.IO;
37 using System.Net;
38 using System.Web;
39 using System.Xml;
40 using System.Text;
41 using System.Reflection;
42 using System.Web.Services;
43 using System.Diagnostics;
44 using System.Runtime.CompilerServices;
45 using System.Web.Services.Description;
46 using System.Web.Services.Discovery;
47 using System.Xml.Serialization;
48 using System.Xml.Schema;
49 using System.Collections;
50 using System.Threading;
52 namespace System.Web.Services.Protocols
54 #if NET_2_0
55 [System.Runtime.InteropServices.ComVisible (true)]
56 #endif
57 public class SoapHttpClientProtocol : HttpWebClientProtocol
59 SoapTypeStubInfo type_info;
60 #if NET_2_0
61 SoapProtocolVersion soapVersion;
62 #endif
64 #region SoapWebClientAsyncResult class
66 internal class SoapWebClientAsyncResult: WebClientAsyncResult
68 public SoapWebClientAsyncResult (WebRequest request, AsyncCallback callback, object asyncState)
69 : base (request, callback, asyncState)
73 public SoapClientMessage Message;
74 public SoapExtension[] Extensions;
76 #endregion
78 #region Constructors
80 public SoapHttpClientProtocol ()
82 type_info = (SoapTypeStubInfo) TypeStubManager.GetTypeStub (this.GetType (), "Soap");
85 #endregion // Constructors
87 #region Methods
89 protected IAsyncResult BeginInvoke (string methodName, object[] parameters, AsyncCallback callback, object asyncState)
91 SoapMethodStubInfo msi = (SoapMethodStubInfo) type_info.GetMethod (methodName);
93 SoapWebClientAsyncResult ainfo = null;
94 try
96 SoapClientMessage message = new SoapClientMessage (this, msi, Url, parameters);
97 message.CollectHeaders (this, message.MethodStubInfo.Headers, SoapHeaderDirection.In);
99 WebRequest request = GetRequestForMessage (uri, message);
101 ainfo = new SoapWebClientAsyncResult (request, callback, asyncState);
102 ainfo.Message = message;
103 ainfo.Extensions = SoapExtension.CreateExtensionChain (type_info.SoapExtensions[0], msi.SoapExtensions, type_info.SoapExtensions[1]);
105 ainfo.Request.BeginGetRequestStream (new AsyncCallback (AsyncGetRequestStreamDone), ainfo);
106 RegisterMapping (asyncState, ainfo);
108 catch (Exception ex)
110 if (ainfo != null)
111 ainfo.SetCompleted (null, ex, false);
114 return ainfo;
117 void AsyncGetRequestStreamDone (IAsyncResult ar)
119 SoapWebClientAsyncResult ainfo = (SoapWebClientAsyncResult) ar.AsyncState;
122 SendRequest (ainfo.Request.EndGetRequestStream (ar), ainfo.Message, ainfo.Extensions);
123 ainfo.Request.BeginGetResponse (new AsyncCallback (AsyncGetResponseDone), ainfo);
125 catch (Exception ex)
127 ainfo.SetCompleted (null, ex, true);
131 void AsyncGetResponseDone (IAsyncResult ar)
133 SoapWebClientAsyncResult ainfo = (SoapWebClientAsyncResult) ar.AsyncState;
134 WebResponse response = null;
136 try {
137 response = GetWebResponse (ainfo.Request, ar);
139 catch (WebException ex) {
140 response = ex.Response;
141 HttpWebResponse http_response = response as HttpWebResponse;
142 if (http_response == null || http_response.StatusCode != HttpStatusCode.InternalServerError) {
143 ainfo.SetCompleted (null, ex, true);
144 return;
147 catch (Exception ex) {
148 ainfo.SetCompleted (null, ex, true);
149 return;
152 try {
153 object[] result = ReceiveResponse (response, ainfo.Message, ainfo.Extensions);
154 ainfo.SetCompleted (result, null, true);
156 catch (Exception ex) {
157 ainfo.SetCompleted (null, ex, true);
159 finally {
160 response.Close();
164 protected object[] EndInvoke (IAsyncResult asyncResult)
166 if (!(asyncResult is SoapWebClientAsyncResult)) throw new ArgumentException ("asyncResult is not the return value from BeginInvoke");
168 SoapWebClientAsyncResult ainfo = (SoapWebClientAsyncResult) asyncResult;
169 lock (ainfo)
171 if (!ainfo.IsCompleted)
172 ainfo.WaitForComplete ();
174 UnregisterMapping (ainfo.AsyncState);
176 if (ainfo.Exception != null)
177 throw ainfo.Exception;
178 else
179 return (object[]) ainfo.Result;
183 public void Discover ()
185 BindingInfo bnd = (BindingInfo) type_info.Bindings [0];
187 DiscoveryClientProtocol discoverer = new DiscoveryClientProtocol ();
188 discoverer.Discover (Url);
190 foreach (object info in discoverer.AdditionalInformation)
192 System.Web.Services.Discovery.SoapBinding sb = info as System.Web.Services.Discovery.SoapBinding;
193 if (sb != null && sb.Binding.Name == bnd.Name && sb.Binding.Namespace == bnd.Namespace) {
194 Url = sb.Address;
195 return;
199 string msg = string.Format (
200 "The binding named '{0}' from namespace '{1}' was not found in the discovery document at '{2}'",
201 bnd.Name, bnd.Namespace, Url);
202 throw new Exception (msg);
205 protected override WebRequest GetWebRequest (Uri uri)
207 return base.GetWebRequest (uri);
210 WebRequest GetRequestForMessage (Uri uri, SoapClientMessage message)
212 WebRequest request = GetWebRequest (uri);
213 request.Method = "POST";
214 WebHeaderCollection headers = request.Headers;
215 if (!message.IsSoap12)
216 headers.Add ("SOAPAction", "\"" + message.Action + "\"");
217 request.ContentType = message.ContentType + "; charset=utf-8";
218 return request;
221 #if NET_2_0
222 [MonoTODO]
223 protected virtual
224 #endif
225 XmlReader GetReaderForMessage (
226 SoapClientMessage message, int bufferSize)
228 throw new NotImplementedException ();
231 #if NET_2_0
232 [MonoTODO]
233 protected virtual
234 #endif
235 XmlWriter GetWriterForMessage (
236 SoapClientMessage message, int bufferSize)
238 throw new NotImplementedException ();
241 void SendRequest (Stream s, SoapClientMessage message, SoapExtension[] extensions)
243 using (s) {
245 if (extensions != null) {
246 s = SoapExtension.ExecuteChainStream (extensions, s);
247 message.SetStage (SoapMessageStage.BeforeSerialize);
248 SoapExtension.ExecuteProcessMessage (extensions, message, s, true);
251 XmlTextWriter xtw = WebServiceHelper.CreateXmlWriter (s);
252 WebServiceHelper.WriteSoapMessage (xtw, message.MethodStubInfo, SoapHeaderDirection.In, message.Parameters, message.Headers, message.IsSoap12);
254 if (extensions != null) {
255 message.SetStage (SoapMessageStage.AfterSerialize);
256 SoapExtension.ExecuteProcessMessage (extensions, message, s, true);
259 xtw.Flush ();
260 xtw.Close ();
266 // TODO:
267 // Handle other web responses (multi-output?)
269 object [] ReceiveResponse (WebResponse response, SoapClientMessage message, SoapExtension[] extensions)
271 SoapMethodStubInfo msi = message.MethodStubInfo;
272 HttpWebResponse http_response = response as HttpWebResponse;
274 if (http_response != null)
276 HttpStatusCode code = http_response.StatusCode;
278 if (!(code == HttpStatusCode.Accepted || code == HttpStatusCode.OK || code == HttpStatusCode.InternalServerError)) {
279 string msg = "The request failed with HTTP status {0}: {1}";
280 msg = String.Format (msg, (int) code, code);
281 throw new WebException (msg, null, WebExceptionStatus.ProtocolError, http_response);
283 if (message.OneWay && response.ContentLength <= 0 && (code == HttpStatusCode.Accepted || code == HttpStatusCode.OK)) {
284 return new object[0];
289 // Remove optional encoding
291 string ctype;
292 Encoding encoding = WebServiceHelper.GetContentEncoding (response.ContentType, out ctype);
293 ctype = ctype.ToLower (CultureInfo.InvariantCulture);
294 #if NET_2_0
295 if ((!message.IsSoap12 || ctype != "application/soap+xml") && ctype != "text/xml")
296 #else
297 if (ctype != "text/xml")
298 #endif
299 WebServiceHelper.InvalidOperation (
300 String.Format ("Not supported Content-Type in the response: '{0}'", response.ContentType),
301 response, encoding);
303 message.ContentType = ctype;
304 message.ContentEncoding = encoding.WebName;
306 Stream stream = response.GetResponseStream ();
308 if (extensions != null) {
309 stream = SoapExtension.ExecuteChainStream (extensions, stream);
310 message.SetStage (SoapMessageStage.BeforeDeserialize);
311 SoapExtension.ExecuteProcessMessage (extensions, message, stream, false);
314 // Deserialize the response
316 SoapHeaderCollection headers;
317 object content;
319 using (StreamReader reader = new StreamReader (stream, encoding, false)) {
320 XmlTextReader xml_reader = new XmlTextReader (reader);
322 WebServiceHelper.ReadSoapMessage (xml_reader, msi, SoapHeaderDirection.Out, message.IsSoap12, out content, out headers);
325 #if NET_2_0
326 if (content is Soap12Fault) {
327 SoapException ex = WebServiceHelper.Soap12FaultToSoapException ((Soap12Fault) content);
328 message.SetException (ex);
330 else
331 #endif
332 if (content is Fault) {
333 Fault fault = (Fault) content;
334 SoapException ex = new SoapException (fault.faultstring, fault.faultcode, fault.faultactor, fault.detail);
335 message.SetException (ex);
337 else
338 message.OutParameters = (object[]) content;
340 message.SetHeaders (headers);
341 message.UpdateHeaderValues (this, message.MethodStubInfo.Headers);
343 if (extensions != null) {
344 message.SetStage (SoapMessageStage.AfterDeserialize);
345 SoapExtension.ExecuteProcessMessage (extensions, message, stream, false);
348 if (message.Exception == null)
349 return message.OutParameters;
350 else
351 throw message.Exception;
354 protected object[] Invoke (string method_name, object[] parameters)
356 SoapMethodStubInfo msi = (SoapMethodStubInfo) type_info.GetMethod (method_name);
358 SoapClientMessage message = new SoapClientMessage (this, msi, Url, parameters);
359 message.CollectHeaders (this, message.MethodStubInfo.Headers, SoapHeaderDirection.In);
361 SoapExtension[] extensions = SoapExtension.CreateExtensionChain (type_info.SoapExtensions[0], msi.SoapExtensions, type_info.SoapExtensions[1]);
363 WebResponse response;
366 WebRequest request = GetRequestForMessage (uri, message);
367 SendRequest (request.GetRequestStream (), message, extensions);
368 response = GetWebResponse (request);
370 catch (WebException ex)
372 response = ex.Response;
373 HttpWebResponse http_response = response as HttpWebResponse;
374 if (http_response == null || http_response.StatusCode != HttpStatusCode.InternalServerError)
375 throw ex;
378 try {
379 return ReceiveResponse (response, message, extensions);
381 finally {
382 response.Close();
386 #if NET_2_0
388 [MonoTODO ("Do something with this")]
389 [System.Runtime.InteropServices.ComVisible(false)]
390 [DefaultValue (SoapProtocolVersion.Default)]
391 public SoapProtocolVersion SoapVersion {
392 get { return soapVersion; }
393 set { soapVersion = value; }
396 protected void InvokeAsync (string methodName, object[] parameters, SendOrPostCallback callback)
398 InvokeAsync (methodName, parameters, callback, null);
401 protected void InvokeAsync (string methodName, object[] parameters, SendOrPostCallback callback, object userState)
403 InvokeAsyncInfo info = new InvokeAsyncInfo (callback, userState);
404 BeginInvoke (methodName, parameters, new AsyncCallback (InvokeAsyncCallback), info);
407 void InvokeAsyncCallback (IAsyncResult ar)
409 InvokeAsyncInfo info = (InvokeAsyncInfo) ar.AsyncState;
410 SoapWebClientAsyncResult sar = (SoapWebClientAsyncResult) ar;
411 InvokeCompletedEventArgs args = new InvokeCompletedEventArgs (sar.Exception, false, info.UserState, (object[]) sar.Result);
412 if (info.Context != null)
413 info.Context.Send (info.Callback, args);
414 else
415 info.Callback (args);
418 #endif
420 #endregion // Methods