2 // System.Web.Services.Protocols.SoapHttpClientProtocol.cs
\r
5 // Tim Coleman (tim@timcoleman.com)
\r
6 // Miguel de Icaza (miguel@ximian.com)
\r
7 // Lluis Sanchez Gual (lluis@ximian.com)
\r
9 // Copyright (C) Tim Coleman, 2002
\r
10 // Copyright (C) Ximian, Inc, 2003
\r
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:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
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.
39 using System.Reflection;
\r
40 using System.Web.Services;
\r
41 using System.Diagnostics;
\r
42 using System.Runtime.CompilerServices;
\r
43 using System.Web.Services.Description;
\r
44 using System.Web.Services.Discovery;
\r
45 using System.Xml.Serialization;
\r
46 using System.Xml.Schema;
\r
47 using System.Collections;
\r
48 using System.Threading;
\r
50 namespace System.Web.Services.Protocols
\r
52 public class SoapHttpClientProtocol : HttpWebClientProtocol
\r
54 SoapTypeStubInfo type_info;
\r
56 WsiClaims conformanceClaims;
\r
57 SoapProtocolVersion soapVersion;
\r
60 #region SoapWebClientAsyncResult class
\r
62 internal class SoapWebClientAsyncResult: WebClientAsyncResult
\r
64 public SoapWebClientAsyncResult (WebRequest request, AsyncCallback callback, object asyncState)
\r
65 : base (request, callback, asyncState)
\r
69 public SoapClientMessage Message;
\r
70 public SoapExtension[] Extensions;
\r
74 #region Constructors
\r
76 public SoapHttpClientProtocol ()
\r
78 type_info = (SoapTypeStubInfo) TypeStubManager.GetTypeStub (this.GetType (), "Soap");
\r
81 #endregion // Constructors
\r
85 protected IAsyncResult BeginInvoke (string methodName, object[] parameters, AsyncCallback callback, object asyncState)
\r
87 SoapMethodStubInfo msi = (SoapMethodStubInfo) type_info.GetMethod (methodName);
\r
89 SoapWebClientAsyncResult ainfo = null;
\r
92 SoapClientMessage message = new SoapClientMessage (this, msi, Url, parameters);
\r
93 message.CollectHeaders (this, message.MethodStubInfo.Headers, SoapHeaderDirection.In);
\r
95 WebRequest request = GetRequestForMessage (uri, message);
\r
97 ainfo = new SoapWebClientAsyncResult (request, callback, asyncState);
\r
98 ainfo.Message = message;
\r
99 ainfo.Extensions = SoapExtension.CreateExtensionChain (type_info.SoapExtensions[0], msi.SoapExtensions, type_info.SoapExtensions[1]);
\r
101 ainfo.Request.BeginGetRequestStream (new AsyncCallback (AsyncGetRequestStreamDone), ainfo);
\r
103 catch (Exception ex)
\r
106 ainfo.SetCompleted (null, ex, false);
\r
112 void AsyncGetRequestStreamDone (IAsyncResult ar)
\r
114 SoapWebClientAsyncResult ainfo = (SoapWebClientAsyncResult) ar.AsyncState;
\r
117 SendRequest (ainfo.Request.EndGetRequestStream (ar), ainfo.Message, ainfo.Extensions);
\r
118 ainfo.Request.BeginGetResponse (new AsyncCallback (AsyncGetResponseDone), ainfo);
\r
120 catch (Exception ex)
\r
122 ainfo.SetCompleted (null, ex, true);
\r
126 void AsyncGetResponseDone (IAsyncResult ar)
\r
128 SoapWebClientAsyncResult ainfo = (SoapWebClientAsyncResult) ar.AsyncState;
\r
129 WebResponse response = null;
\r
132 response = GetWebResponse (ainfo.Request, ar);
\r
134 catch (WebException ex) {
\r
135 response = ex.Response;
\r
136 HttpWebResponse http_response = response as HttpWebResponse;
\r
137 if (http_response == null || http_response.StatusCode != HttpStatusCode.InternalServerError) {
\r
138 ainfo.SetCompleted (null, ex, true);
\r
142 catch (Exception ex) {
\r
143 ainfo.SetCompleted (null, ex, true);
\r
148 object[] result = ReceiveResponse (response, ainfo.Message, ainfo.Extensions);
\r
149 ainfo.SetCompleted (result, null, true);
\r
151 catch (Exception ex) {
\r
152 ainfo.SetCompleted (null, ex, true);
\r
156 protected object[] EndInvoke (IAsyncResult asyncResult)
\r
158 if (!(asyncResult is SoapWebClientAsyncResult)) throw new ArgumentException ("asyncResult is not the return value from BeginInvoke");
\r
160 SoapWebClientAsyncResult ainfo = (SoapWebClientAsyncResult) asyncResult;
\r
163 if (!ainfo.IsCompleted) ainfo.WaitForComplete ();
\r
164 if (ainfo.Exception != null) throw ainfo.Exception;
\r
165 else return (object[]) ainfo.Result;
\r
169 public void Discover ()
\r
171 BindingInfo bnd = (BindingInfo) type_info.Bindings [0];
\r
173 DiscoveryClientProtocol discoverer = new DiscoveryClientProtocol ();
\r
174 discoverer.Discover (Url);
\r
176 foreach (object info in discoverer.AdditionalInformation)
\r
178 System.Web.Services.Discovery.SoapBinding sb = info as System.Web.Services.Discovery.SoapBinding;
\r
179 if (sb != null && sb.Binding.Name == bnd.Name && sb.Binding.Namespace == bnd.Namespace) {
\r
185 string msg = string.Format ("The binding named '{0}' from namespace '{1}' was not found in the discovery document at '{2}'", bnd.Name, bnd.Namespace, Url);
\r
186 throw new Exception (msg);
\r
189 protected override WebRequest GetWebRequest (Uri uri)
\r
191 return base.GetWebRequest (uri);
\r
194 WebRequest GetRequestForMessage (Uri uri, SoapClientMessage message)
\r
196 WebRequest request = GetWebRequest (uri);
\r
197 request.Method = "POST";
\r
198 WebHeaderCollection headers = request.Headers;
\r
199 headers.Add ("SOAPAction", "\"" + message.Action + "\"");
\r
200 request.ContentType = message.ContentType + "; charset=utf-8";
\r
204 void SendRequest (Stream s, SoapClientMessage message, SoapExtension[] extensions)
\r
208 if (extensions != null) {
\r
209 s = SoapExtension.ExecuteChainStream (extensions, s);
\r
210 message.SetStage (SoapMessageStage.BeforeSerialize);
\r
211 SoapExtension.ExecuteProcessMessage (extensions, message, true);
214 XmlTextWriter xtw = WebServiceHelper.CreateXmlWriter (s);
\r
216 WebServiceHelper.WriteSoapMessage (xtw, type_info, message.MethodStubInfo.Use, message.MethodStubInfo.RequestSerializer, message.Parameters, message.Headers);
\r
218 if (extensions != null) {
\r
219 message.SetStage (SoapMessageStage.AfterSerialize);
\r
220 SoapExtension.ExecuteProcessMessage (extensions, message, true);
231 // Handle other web responses (multi-output?)
\r
233 object [] ReceiveResponse (WebResponse response, SoapClientMessage message, SoapExtension[] extensions)
\r
235 SoapMethodStubInfo msi = message.MethodStubInfo;
\r
236 HttpWebResponse http_response = response as HttpWebResponse;
\r
238 if (http_response != null)
\r
240 HttpStatusCode code = http_response.StatusCode;
\r
242 if (!(code == HttpStatusCode.Accepted || code == HttpStatusCode.OK || code == HttpStatusCode.InternalServerError)) {
\r
243 string msg = "The request failed with HTTP status {0}: {1}";
\r
244 msg = String.Format (msg, (int) code, code);
\r
245 throw new WebException (msg, null, WebExceptionStatus.ProtocolError, http_response);
\r
247 if (response.ContentLength == 0 && (code == HttpStatusCode.Accepted || code == HttpStatusCode.OK)) {
\r
248 return new object[0];
\r
253 // Remove optional encoding
\r
256 Encoding encoding = WebServiceHelper.GetContentEncoding (response.ContentType, out ctype);
\r
257 if (ctype != "text/xml")
258 WebServiceHelper.InvalidOperation (
259 "Content is not 'text/xml' but '" + response.ContentType + "'",
262 message.ContentType = ctype;
\r
263 message.ContentEncoding = encoding.WebName;
\r
265 Stream stream = response.GetResponseStream ();
\r
267 if (extensions != null) {
\r
268 stream = SoapExtension.ExecuteChainStream (extensions, stream);
\r
269 message.SetStage (SoapMessageStage.BeforeDeserialize);
\r
270 SoapExtension.ExecuteProcessMessage (extensions, message, false);
273 // Deserialize the response
\r
275 SoapHeaderCollection headers;
\r
278 using (StreamReader reader = new StreamReader (stream, encoding, false)) {
279 XmlTextReader xml_reader = new XmlTextReader (reader);
281 WebServiceHelper.ReadSoapMessage (xml_reader, type_info, msi.Use, msi.ResponseSerializer,
282 out content, out headers);
286 if (content is Fault)
\r
288 Fault fault = (Fault) content;
\r
289 SoapException ex = new SoapException (fault.faultstring, fault.faultcode, fault.faultactor, fault.detail);
\r
290 message.SetException (ex);
\r
293 message.OutParameters = (object[]) content;
\r
295 message.SetHeaders (headers);
\r
296 message.UpdateHeaderValues (this, message.MethodStubInfo.Headers);
\r
298 if (extensions != null) {
\r
299 message.SetStage (SoapMessageStage.AfterDeserialize);
\r
300 SoapExtension.ExecuteProcessMessage (extensions, message, false);
303 if (message.Exception == null)
\r
304 return message.OutParameters;
\r
306 throw message.Exception;
\r
309 protected object[] Invoke (string method_name, object[] parameters)
\r
311 SoapMethodStubInfo msi = (SoapMethodStubInfo) type_info.GetMethod (method_name);
\r
313 SoapClientMessage message = new SoapClientMessage (this, msi, Url, parameters);
\r
314 message.CollectHeaders (this, message.MethodStubInfo.Headers, SoapHeaderDirection.In);
\r
316 SoapExtension[] extensions = SoapExtension.CreateExtensionChain (type_info.SoapExtensions[0], msi.SoapExtensions, type_info.SoapExtensions[1]);
\r
318 WebResponse response;
\r
321 WebRequest request = GetRequestForMessage (uri, message);
\r
322 SendRequest (request.GetRequestStream (), message, extensions);
\r
323 response = GetWebResponse (request);
\r
325 catch (WebException ex)
\r
327 response = ex.Response;
\r
328 HttpWebResponse http_response = response as HttpWebResponse;
\r
329 if (http_response == null || http_response.StatusCode != HttpStatusCode.InternalServerError)
\r
333 return ReceiveResponse (response, message, extensions);
\r
338 [MonoTODO ("Do something with this")]
\r
339 [System.Runtime.InteropServices.ComVisible(false)]
\r
341 public WsiClaims ConformanceClaims {
\r
342 get { return conformanceClaims; }
\r
343 set { conformanceClaims = value; }
\r
346 [MonoTODO ("Do something with this")]
\r
347 [System.Runtime.InteropServices.ComVisible(false)]
\r
348 public SoapProtocolVersion SoapVersion {
\r
349 get { return soapVersion; }
\r
350 set { soapVersion = value; }
\r
353 protected void InvokeAsync (string methodName, object[] parameters, SendOrPostCallback callback)
\r
355 InvokeAsync (methodName, parameters, callback, null);
\r
358 protected void InvokeAsync (string methodName, object[] parameters, SendOrPostCallback callback, object userState)
\r
360 InvokeAsyncInfo info = new InvokeAsyncInfo (callback, userState);
\r
361 BeginInvoke (methodName, parameters, new AsyncCallback (InvokeAsyncCallback), info);
\r
364 void InvokeAsyncCallback (IAsyncResult ar)
\r
366 InvokeAsyncInfo info = (InvokeAsyncInfo) ar.AsyncState;
\r
367 SoapWebClientAsyncResult sar = (SoapWebClientAsyncResult) ar;
\r
368 InvokeCompletedEventArgs args = new InvokeCompletedEventArgs (sar.Exception, false, info.UserState, (object[]) sar.Result);
\r
369 if (info.Context != null)
\r
370 info.Context.SendOrPost (info.Callback, args);
\r
372 info.Callback (args);
\r
377 #endregion // Methods
\r