// Copyright (C) Tim Coleman, 2002\r
// Copyright (C) Ximian, Inc, 2003\r
//\r
+
+//
+// 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.
+//
\r
using System.IO;\r
using System.Net;\r
using System.Diagnostics;\r
using System.Runtime.CompilerServices;\r
using System.Web.Services.Description;\r
+using System.Web.Services.Discovery;\r
using System.Xml.Serialization;\r
using System.Xml.Schema;\r
using System.Collections;\r
using System.Threading;\r
\r
-namespace System.Web.Services.Protocols {\r
- public class SoapHttpClientProtocol : HttpWebClientProtocol {\r
+namespace System.Web.Services.Protocols \r
+{\r
+ public class SoapHttpClientProtocol : HttpWebClientProtocol \r
+ {\r
SoapTypeStubInfo type_info;\r
+#if NET_2_0\r
+ WsiClaims conformanceClaims;\r
+ SoapProtocolVersion soapVersion;\r
+#endif\r
\r
- #region AsyncInfo class\r
+ #region SoapWebClientAsyncResult class\r
\r
- internal class AsyncInfo: IAsyncResult\r
+ internal class SoapWebClientAsyncResult: WebClientAsyncResult\r
{\r
- bool _completedSynchronously;\r
- bool _done;\r
- ManualResetEvent _waitHandle;\r
-\r
- public object AsyncState \r
- {\r
- get { return InternalAsyncState; }\r
- }\r
-\r
- public WaitHandle AsyncWaitHandle \r
- {\r
- get\r
- {\r
- lock (this) {\r
- if (_waitHandle != null) return _waitHandle;\r
- _waitHandle = new ManualResetEvent (_done);\r
- return _waitHandle;\r
- }\r
- }\r
- }\r
-\r
- public bool CompletedSynchronously \r
+ public SoapWebClientAsyncResult (WebRequest request, AsyncCallback callback, object asyncState)\r
+ : base (request, callback, asyncState)\r
{\r
- get { return _completedSynchronously; }\r
- }\r
-\r
- public bool IsCompleted \r
- {\r
- get { lock (this) { return _done; } }\r
- }\r
-\r
- internal void SetCompleted (object[] result, Exception exception, bool async)\r
- {\r
- lock (this)\r
- {\r
- Exception = exception;\r
- Result = result;\r
- _done = true;\r
- _completedSynchronously = async;\r
- if (_waitHandle != null) _waitHandle.Set ();\r
- Monitor.PulseAll (this);\r
- }\r
- if (Callback != null) Callback (this);\r
- }\r
-\r
- internal void WaitForComplete ()\r
- {\r
- lock (this)\r
- {\r
- Monitor.Wait (this);\r
- }\r
}\r
-\r
- internal object InternalAsyncState;\r
- internal AsyncCallback Callback;\r
- internal SoapClientMessage Message;\r
- internal SoapExtension[] Extensions;\r
- internal WebRequest Request;\r
- internal object[] Result;\r
- internal Exception Exception;\r
+ \r
+ public SoapClientMessage Message;\r
+ public SoapExtension[] Extensions;\r
}\r
#endregion\r
\r
\r
public SoapHttpClientProtocol () \r
{\r
- type_info = (SoapTypeStubInfo) TypeStubManager.GetTypeStub (this.GetType (), typeof(SoapTypeStubInfo));\r
+ type_info = (SoapTypeStubInfo) TypeStubManager.GetTypeStub (this.GetType (), "Soap");\r
}\r
\r
#endregion // Constructors\r
\r
protected IAsyncResult BeginInvoke (string methodName, object[] parameters, AsyncCallback callback, object asyncState)\r
{\r
- AsyncInfo ainfo = new AsyncInfo ();\r
-\r
SoapMethodStubInfo msi = (SoapMethodStubInfo) type_info.GetMethod (methodName);\r
- ainfo.Message = new SoapClientMessage (this, msi, Url, parameters);\r
- ainfo.Message.CollectHeaders (this, ainfo.Message.MethodStubInfo.Headers, SoapHeaderDirection.In);\r
- ainfo.Extensions = SoapExtension.CreateExtensionChain (type_info.SoapExtensions[0], msi.SoapExtensions, type_info.SoapExtensions[1]);\r
- ainfo.InternalAsyncState = asyncState;\r
- ainfo.Callback = callback;\r
\r
+ SoapWebClientAsyncResult ainfo = null;\r
try\r
{\r
- ainfo.Request = GetRequestForMessage (uri, ainfo.Message);\r
+ SoapClientMessage message = new SoapClientMessage (this, msi, Url, parameters);\r
+ message.CollectHeaders (this, message.MethodStubInfo.Headers, SoapHeaderDirection.In);\r
+ \r
+ WebRequest request = GetRequestForMessage (uri, message);\r
+ \r
+ ainfo = new SoapWebClientAsyncResult (request, callback, asyncState);\r
+ ainfo.Message = message;\r
+ ainfo.Extensions = SoapExtension.CreateExtensionChain (type_info.SoapExtensions[0], msi.SoapExtensions, type_info.SoapExtensions[1]);\r
+\r
ainfo.Request.BeginGetRequestStream (new AsyncCallback (AsyncGetRequestStreamDone), ainfo);\r
}\r
catch (Exception ex)\r
{\r
- ainfo.SetCompleted (null, ex, false);\r
+ if (ainfo != null)\r
+ ainfo.SetCompleted (null, ex, false);\r
}\r
\r
return ainfo;\r
\r
void AsyncGetRequestStreamDone (IAsyncResult ar)\r
{\r
- AsyncInfo ainfo = (AsyncInfo) ar.AsyncState;\r
+ SoapWebClientAsyncResult ainfo = (SoapWebClientAsyncResult) ar.AsyncState;\r
try\r
{\r
SendRequest (ainfo.Request.EndGetRequestStream (ar), ainfo.Message, ainfo.Extensions);\r
-\r
ainfo.Request.BeginGetResponse (new AsyncCallback (AsyncGetResponseDone), ainfo);\r
}\r
catch (Exception ex)\r
\r
void AsyncGetResponseDone (IAsyncResult ar)\r
{\r
- AsyncInfo ainfo = (AsyncInfo) ar.AsyncState;\r
+ SoapWebClientAsyncResult ainfo = (SoapWebClientAsyncResult) ar.AsyncState;\r
WebResponse response = null;\r
\r
try {\r
\r
protected object[] EndInvoke (IAsyncResult asyncResult)\r
{\r
- if (!(asyncResult is AsyncInfo)) throw new ArgumentException ("asyncResult is not the return value from BeginInvoke");\r
+ if (!(asyncResult is SoapWebClientAsyncResult)) throw new ArgumentException ("asyncResult is not the return value from BeginInvoke");\r
\r
- AsyncInfo ainfo = (AsyncInfo) asyncResult;\r
+ SoapWebClientAsyncResult ainfo = (SoapWebClientAsyncResult) asyncResult;\r
lock (ainfo)\r
{\r
if (!ainfo.IsCompleted) ainfo.WaitForComplete ();\r
if (ainfo.Exception != null) throw ainfo.Exception;\r
- else return ainfo.Result;\r
+ else return (object[]) ainfo.Result;\r
}\r
}\r
\r
- [MonoTODO]\r
public void Discover ()\r
{\r
- throw new NotImplementedException ();\r
+ BindingInfo bnd = (BindingInfo) type_info.Bindings [0];\r
+ \r
+ DiscoveryClientProtocol discoverer = new DiscoveryClientProtocol ();\r
+ discoverer.Discover (Url);\r
+ \r
+ foreach (object info in discoverer.AdditionalInformation)\r
+ {\r
+ System.Web.Services.Discovery.SoapBinding sb = info as System.Web.Services.Discovery.SoapBinding;\r
+ if (sb != null && sb.Binding.Name == bnd.Name && sb.Binding.Namespace == bnd.Namespace) {\r
+ Url = sb.Address;\r
+ return;\r
+ }\r
+ }\r
+ \r
+ 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
+ throw new Exception (msg);\r
}\r
\r
protected override WebRequest GetWebRequest (Uri uri)\r
return base.GetWebRequest (uri);\r
}\r
\r
- //\r
- // Just for debugging\r
- //\r
- void DumpStackFrames ()\r
- {\r
- StackTrace st = new StackTrace ();\r
-\r
- for (int i = 0; i < st.FrameCount; i++){\r
- StackFrame sf = st.GetFrame (i);\r
- Console.WriteLine ("At frame: {0} {1}", i, sf.GetMethod ().Name);\r
- }\r
- }\r
-\r
WebRequest GetRequestForMessage (Uri uri, SoapClientMessage message)\r
{\r
WebRequest request = GetWebRequest (uri);\r
request.Method = "POST";\r
WebHeaderCollection headers = request.Headers;\r
- headers.Add ("SOAPAction", message.Action);\r
+ headers.Add ("SOAPAction", "\"" + message.Action + "\"");\r
request.ContentType = message.ContentType + "; charset=utf-8";\r
return request;\r
}\r
SoapExtension.ExecuteProcessMessage (extensions, message, true);
}
\r
- // What a waste of UTF8encoders, but it has to be thread safe.\r
- XmlTextWriter xtw = new XmlTextWriter (s, new UTF8Encoding (false));\r
- xtw.Formatting = Formatting.Indented;\r
-\r
- WebServiceHelper.WriteSoapMessage (xtw, type_info, message.MethodStubInfo.RequestSerializer, message.Parameters, message.Headers);\r
+ XmlTextWriter xtw = WebServiceHelper.CreateXmlWriter (s);\r
+ \r
+ WebServiceHelper.WriteSoapMessage (xtw, type_info, message.MethodStubInfo.Use, message.MethodStubInfo.RequestSerializer, message.Parameters, message.Headers);\r
\r
if (extensions != null) {\r
message.SetStage (SoapMessageStage.AfterSerialize);\r
// \r
object [] ReceiveResponse (WebResponse response, SoapClientMessage message, SoapExtension[] extensions)\r
{\r
- HttpWebResponse http_response = (HttpWebResponse) response;\r
- HttpStatusCode code = http_response.StatusCode;\r
SoapMethodStubInfo msi = message.MethodStubInfo;\r
-\r
- if (!(code == HttpStatusCode.Accepted || code == HttpStatusCode.OK || code == HttpStatusCode.InternalServerError))\r
- throw new Exception ("Return code was: " + http_response.StatusCode);\r
-\r
+ HttpWebResponse http_response = response as HttpWebResponse;\r
+ \r
+ if (http_response != null)\r
+ {\r
+ HttpStatusCode code = http_response.StatusCode;\r
+ \r
+ if (!(code == HttpStatusCode.Accepted || code == HttpStatusCode.OK || code == HttpStatusCode.InternalServerError)) {\r
+ string msg = "The request failed with HTTP status {0}: {1}";\r
+ msg = String.Format (msg, (int) code, code);\r
+ throw new WebException (msg, null, WebExceptionStatus.ProtocolError, http_response);\r
+ }\r
+ if (response.ContentLength == 0 && (code == HttpStatusCode.Accepted || code == HttpStatusCode.OK)) {\r
+ return new object[0];\r
+ }\r
+ }\r
+ \r
//\r
// Remove optional encoding\r
//\r
- Encoding encoding = WebServiceHelper.GetContentEncoding (response.ContentType);\r
-\r
+ string ctype;
+ Encoding encoding = WebServiceHelper.GetContentEncoding (response.ContentType, out ctype);\r
+ if (ctype != "text/xml")
+ WebServiceHelper.InvalidOperation (
+ "Content is not 'text/xml' but '" + response.ContentType + "'",
+ response, encoding);
+\r
+ message.ContentType = ctype;\r
+ message.ContentEncoding = encoding.WebName;\r
+ \r
Stream stream = response.GetResponseStream ();\r
\r
if (extensions != null) {\r
\r
// Deserialize the response\r
\r
- StreamReader reader = new StreamReader (stream, encoding, false);\r
- XmlTextReader xml_reader = new XmlTextReader (reader);\r
-\r
- bool isSuccessful = (code != HttpStatusCode.InternalServerError);\r
SoapHeaderCollection headers;\r
object content;\r
\r
- if (isSuccessful) {\r
- WebServiceHelper.ReadSoapMessage (xml_reader, type_info, msi.ResponseSerializer, out content, out headers);\r
- message.OutParameters = (object[]) content;\r
- }\r
- else {\r
- WebServiceHelper.ReadSoapMessage (xml_reader, type_info, type_info.FaultSerializer, out content, out headers);\r
+ using (StreamReader reader = new StreamReader (stream, encoding, false)) {
+ XmlTextReader xml_reader = new XmlTextReader (reader);
+
+ WebServiceHelper.ReadSoapMessage (xml_reader, type_info, msi.Use, msi.ResponseSerializer,
+ out content, out headers);
+ }
+
+ \r
+ if (content is Fault)\r
+ {\r
Fault fault = (Fault) content;\r
SoapException ex = new SoapException (fault.faultstring, fault.faultcode, fault.faultactor, fault.detail);\r
message.SetException (ex);\r
}\r
-\r
+ else\r
+ message.OutParameters = (object[]) content;\r
+ \r
message.SetHeaders (headers);\r
message.UpdateHeaderValues (this, message.MethodStubInfo.Headers);\r
\r
SoapExtension.ExecuteProcessMessage (extensions, message, false);
}
\r
- if (isSuccessful)\r
+ if (message.Exception == null)\r
return message.OutParameters;\r
else\r
throw message.Exception;\r
\r
return ReceiveResponse (response, message, extensions);\r
}\r
+ \r
+#if NET_2_0\r
+\r
+ [MonoTODO ("Do something with this")]\r
+ [System.Runtime.InteropServices.ComVisible(false)]\r
+ [Obsolete]\r
+ public WsiClaims ConformanceClaims {\r
+ get { return conformanceClaims; }\r
+ set { conformanceClaims = value; }\r
+ }\r
+ \r
+ [MonoTODO ("Do something with this")]\r
+ [System.Runtime.InteropServices.ComVisible(false)]\r
+ public SoapProtocolVersion SoapVersion {\r
+ get { return soapVersion; }\r
+ set { soapVersion = value; }\r
+ }\r
+ \r
+ protected void InvokeAsync (string methodName, object[] parameters, SendOrPostCallback callback)\r
+ {\r
+ InvokeAsync (methodName, parameters, callback, null);\r
+ }\r
+\r
+ protected void InvokeAsync (string methodName, object[] parameters, SendOrPostCallback callback, object userState)\r
+ {\r
+ InvokeAsyncInfo info = new InvokeAsyncInfo (callback, userState);\r
+ BeginInvoke (methodName, parameters, new AsyncCallback (InvokeAsyncCallback), info);\r
+ }\r
+ \r
+ void InvokeAsyncCallback (IAsyncResult ar)\r
+ {\r
+ InvokeAsyncInfo info = (InvokeAsyncInfo) ar.AsyncState;\r
+ SoapWebClientAsyncResult sar = (SoapWebClientAsyncResult) ar;\r
+ InvokeCompletedEventArgs args = new InvokeCompletedEventArgs (sar.Exception, false, info.UserState, (object[]) sar.Result);\r
+ if (info.Context != null)\r
+ info.Context.SendOrPost (info.Callback, args);\r
+ else\r
+ info.Callback (args);\r
+ }\r
+\r
+#endif\r
\r
#endregion // Methods\r
}\r
}
+\r