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
18 using System.Reflection;
\r
19 using System.Web.Services;
\r
20 using System.Diagnostics;
\r
21 using System.Runtime.CompilerServices;
\r
22 using System.Web.Services.Description;
\r
23 using System.Xml.Serialization;
\r
24 using System.Xml.Schema;
\r
25 using System.Collections;
\r
26 using System.Threading;
\r
28 namespace System.Web.Services.Protocols {
\r
29 public class SoapHttpClientProtocol : HttpWebClientProtocol {
\r
30 SoapTypeStubInfo type_info;
\r
32 #region AsyncInfo class
\r
34 internal class AsyncInfo: IAsyncResult
\r
36 bool _completedSynchronously;
\r
38 ManualResetEvent _waitHandle;
\r
40 public object AsyncState
\r
42 get { return InternalAsyncState; }
\r
45 public WaitHandle AsyncWaitHandle
\r
50 if (_waitHandle != null) return _waitHandle;
\r
51 _waitHandle = new ManualResetEvent (_done);
\r
57 public bool CompletedSynchronously
\r
59 get { return _completedSynchronously; }
\r
62 public bool IsCompleted
\r
64 get { lock (this) { return _done; } }
\r
67 internal void SetCompleted (object[] result, Exception exception, bool async)
\r
71 Exception = exception;
\r
74 _completedSynchronously = async;
\r
75 if (_waitHandle != null) _waitHandle.Set ();
\r
76 Monitor.PulseAll (this);
\r
78 if (Callback != null) Callback (this);
\r
81 internal void WaitForComplete ()
\r
85 Monitor.Wait (this);
\r
89 internal object InternalAsyncState;
\r
90 internal AsyncCallback Callback;
\r
91 internal SoapClientMessage Message;
\r
92 internal SoapExtension[] Extensions;
\r
93 internal WebRequest Request;
\r
94 internal object[] Result;
\r
95 internal Exception Exception;
\r
99 #region Constructors
\r
101 public SoapHttpClientProtocol ()
\r
103 type_info = (SoapTypeStubInfo) TypeStubManager.GetTypeStub (this.GetType (), typeof(SoapTypeStubInfo));
\r
106 #endregion // Constructors
\r
110 protected IAsyncResult BeginInvoke (string methodName, object[] parameters, AsyncCallback callback, object asyncState)
\r
112 AsyncInfo ainfo = new AsyncInfo ();
\r
114 SoapMethodStubInfo msi = (SoapMethodStubInfo) type_info.GetMethod (methodName);
\r
115 ainfo.Message = new SoapClientMessage (this, msi, Url, parameters);
\r
116 ainfo.Message.CollectHeaders (this, ainfo.Message.MethodStubInfo.Headers, SoapHeaderDirection.In);
\r
117 ainfo.Extensions = SoapExtension.CreateExtensionChain (type_info.SoapExtensions[0], msi.SoapExtensions, type_info.SoapExtensions[1]);
\r
118 ainfo.InternalAsyncState = asyncState;
\r
119 ainfo.Callback = callback;
\r
123 ainfo.Request = GetRequestForMessage (uri, ainfo.Message);
\r
124 ainfo.Request.BeginGetRequestStream (new AsyncCallback (AsyncGetRequestStreamDone), ainfo);
\r
126 catch (Exception ex)
\r
128 ainfo.SetCompleted (null, ex, false);
\r
134 void AsyncGetRequestStreamDone (IAsyncResult ar)
\r
136 AsyncInfo ainfo = (AsyncInfo) ar.AsyncState;
\r
139 SendRequest (ainfo.Request.EndGetRequestStream (ar), ainfo.Message, ainfo.Extensions);
\r
141 ainfo.Request.BeginGetResponse (new AsyncCallback (AsyncGetResponseDone), ainfo);
\r
143 catch (Exception ex)
\r
145 ainfo.SetCompleted (null, ex, true);
\r
149 void AsyncGetResponseDone (IAsyncResult ar)
\r
151 AsyncInfo ainfo = (AsyncInfo) ar.AsyncState;
\r
152 WebResponse response = null;
\r
155 response = GetWebResponse (ainfo.Request, ar);
\r
157 catch (WebException ex) {
\r
158 response = ex.Response;
\r
159 HttpWebResponse http_response = response as HttpWebResponse;
\r
160 if (http_response == null || http_response.StatusCode != HttpStatusCode.InternalServerError) {
\r
161 ainfo.SetCompleted (null, ex, true);
\r
165 catch (Exception ex) {
\r
166 ainfo.SetCompleted (null, ex, true);
\r
171 object[] result = ReceiveResponse (response, ainfo.Message, ainfo.Extensions);
\r
172 ainfo.SetCompleted (result, null, true);
\r
174 catch (Exception ex) {
\r
175 ainfo.SetCompleted (null, ex, true);
\r
179 protected object[] EndInvoke (IAsyncResult asyncResult)
\r
181 if (!(asyncResult is AsyncInfo)) throw new ArgumentException ("asyncResult is not the return value from BeginInvoke");
\r
183 AsyncInfo ainfo = (AsyncInfo) asyncResult;
\r
186 if (!ainfo.IsCompleted) ainfo.WaitForComplete ();
\r
187 if (ainfo.Exception != null) throw ainfo.Exception;
\r
188 else return ainfo.Result;
\r
193 public void Discover ()
\r
195 throw new NotImplementedException ();
\r
198 protected override WebRequest GetWebRequest (Uri uri)
\r
200 return base.GetWebRequest (uri);
\r
204 // Just for debugging
\r
206 void DumpStackFrames ()
\r
208 StackTrace st = new StackTrace ();
\r
210 for (int i = 0; i < st.FrameCount; i++){
\r
211 StackFrame sf = st.GetFrame (i);
\r
212 Console.WriteLine ("At frame: {0} {1}", i, sf.GetMethod ().Name);
\r
216 WebRequest GetRequestForMessage (Uri uri, SoapClientMessage message)
\r
218 WebRequest request = GetWebRequest (uri);
\r
219 request.Method = "POST";
\r
220 WebHeaderCollection headers = request.Headers;
\r
221 headers.Add ("SOAPAction", message.Action);
\r
222 request.ContentType = message.ContentType + "; charset=utf-8";
\r
226 void SendRequest (Stream s, SoapClientMessage message, SoapExtension[] extensions)
\r
230 if (extensions != null) {
\r
231 s = SoapExtension.ExecuteChainStream (extensions, s);
\r
232 message.SetStage (SoapMessageStage.BeforeSerialize);
\r
233 SoapExtension.ExecuteProcessMessage (extensions, message, true);
236 // What a waste of UTF8encoders, but it has to be thread safe.
\r
237 XmlTextWriter xtw = new XmlTextWriter (s, new UTF8Encoding (false));
\r
238 xtw.Formatting = Formatting.Indented;
\r
240 WebServiceHelper.WriteSoapMessage (xtw, type_info, message.MethodStubInfo.RequestSerializer, message.Parameters, message.Headers);
\r
242 if (extensions != null) {
\r
243 message.SetStage (SoapMessageStage.AfterSerialize);
\r
244 SoapExtension.ExecuteProcessMessage (extensions, message, true);
255 // Handle other web responses (multi-output?)
\r
257 object [] ReceiveResponse (WebResponse response, SoapClientMessage message, SoapExtension[] extensions)
\r
259 HttpWebResponse http_response = (HttpWebResponse) response;
\r
260 HttpStatusCode code = http_response.StatusCode;
\r
261 SoapMethodStubInfo msi = message.MethodStubInfo;
\r
263 if (!(code == HttpStatusCode.Accepted || code == HttpStatusCode.OK || code == HttpStatusCode.InternalServerError))
\r
264 throw new Exception ("Return code was: " + http_response.StatusCode);
\r
267 // Remove optional encoding
\r
269 Encoding encoding = WebServiceHelper.GetContentEncoding (response.ContentType);
\r
271 Stream stream = response.GetResponseStream ();
\r
273 if (extensions != null) {
\r
274 stream = SoapExtension.ExecuteChainStream (extensions, stream);
\r
275 message.SetStage (SoapMessageStage.BeforeDeserialize);
\r
276 SoapExtension.ExecuteProcessMessage (extensions, message, false);
279 // Deserialize the response
\r
281 StreamReader reader = new StreamReader (stream, encoding, false);
\r
282 XmlTextReader xml_reader = new XmlTextReader (reader);
\r
284 bool isSuccessful = (code != HttpStatusCode.InternalServerError);
\r
285 SoapHeaderCollection headers;
\r
288 if (isSuccessful) {
\r
289 WebServiceHelper.ReadSoapMessage (xml_reader, type_info, msi.ResponseSerializer, out content, out headers);
\r
290 message.OutParameters = (object[]) content;
\r
293 WebServiceHelper.ReadSoapMessage (xml_reader, type_info, type_info.FaultSerializer, out content, out headers);
\r
294 Fault fault = (Fault) content;
\r
295 SoapException ex = new SoapException (fault.faultstring, fault.faultcode, fault.faultactor, fault.detail);
\r
296 message.SetException (ex);
\r
299 message.SetHeaders (headers);
\r
300 message.UpdateHeaderValues (this, message.MethodStubInfo.Headers);
\r
302 if (extensions != null) {
\r
303 message.SetStage (SoapMessageStage.AfterDeserialize);
\r
304 SoapExtension.ExecuteProcessMessage (extensions, message, false);
308 return message.OutParameters;
\r
310 throw message.Exception;
\r
313 protected object[] Invoke (string method_name, object[] parameters)
\r
315 SoapMethodStubInfo msi = (SoapMethodStubInfo) type_info.GetMethod (method_name);
\r
317 SoapClientMessage message = new SoapClientMessage (this, msi, Url, parameters);
\r
318 message.CollectHeaders (this, message.MethodStubInfo.Headers, SoapHeaderDirection.In);
\r
320 SoapExtension[] extensions = SoapExtension.CreateExtensionChain (type_info.SoapExtensions[0], msi.SoapExtensions, type_info.SoapExtensions[1]);
\r
322 WebResponse response;
\r
325 WebRequest request = GetRequestForMessage (uri, message);
\r
326 SendRequest (request.GetRequestStream (), message, extensions);
\r
327 response = GetWebResponse (request);
\r
329 catch (WebException ex)
\r
331 response = ex.Response;
\r
332 HttpWebResponse http_response = response as HttpWebResponse;
\r
333 if (http_response == null || http_response.StatusCode != HttpStatusCode.InternalServerError)
\r
337 return ReceiveResponse (response, message, extensions);
\r
340 #endregion // Methods
\r