+2003-07-09 Lluis Sanchez Gual <lluis@ximian.com>
+
+ * SoapHttpClientProtocol.cs, HttpSoapWebServiceHandler.cs, Methods.cs:
+ Added support for soap extensions. Moved some code to
+ WebServiceHelper. Implemented support for the two types of RoutingStyle. Added support
+ for In and Out headers. Improved management of exceptions.
+ * SoapClientMessage.cs: code to retrieve soap headers moved to SoapMessage.
+ * SoapExtension.cs: Added methods for getting and creating soap extensions.
+ * SoapMessage.cs: Added methods for getting and assigning headers to an object.
+ * SoapServerMessage.cs: Added setter for MethodStubInfo. Other minor fixes.
+ * WebServiceHandler.cs: Added support for In and Out headers. Fixed management of exceptions.
+ * WebServiceHandlerFactory.cs: Check if the request protocol is supported.
+ * WebServiceHelper.cs: Added method for reading a soap request.
+
2003-07-04 Lluis Sanchez Gual <lluis@ximian.com>
* LogicalMethodInfo.cs: Fixed Invoke method. If return type is void,
{
Type _type;
TypeStubInfo _typeStubInfo;
+ SoapExtension[] _extensionChainHighPrio;
+ SoapExtension[] _extensionChainMedPrio;
+ SoapExtension[] _extensionChainLowPrio;
public HttpSoapWebServiceHandler (Type type)
{
{
SerializeFault (context, requestMessage, ex);
return;
-
-
}
}
using (stream)
{
+ string soapAction = null;
+ MethodStubInfo methodInfo = null;
Encoding encoding = WebServiceHelper.GetContentEncoding (request.ContentType);
- StreamReader reader = new StreamReader (stream, encoding, false);
- XmlTextReader xmlReader = new XmlTextReader (reader);
-
- xmlReader.MoveToContent ();
- xmlReader.ReadStartElement ("Envelope", WebServiceHelper.SoapEnvelopeNamespace);
-
- SoapHeaderCollection headers = ReadHeaders (xmlReader);
+ object server = Activator.CreateInstance (_type);
- xmlReader.MoveToContent ();
- xmlReader.ReadStartElement ("Body", WebServiceHelper.SoapEnvelopeNamespace);
- xmlReader.MoveToContent ();
+ SoapServerMessage message = new SoapServerMessage (request, server, stream);
+ message.SetStage (SoapMessageStage.BeforeDeserialize);
- string methodName;
- string methodNamespace;
- string soapAction = request.Headers ["SOAPAction"];
+ // If the routing style is SoapAction, then we can get the method information now
+ // and set it to the SoapMessage
- if (_typeStubInfo.RoutingStyle == SoapServiceRoutingStyle.SoapAction)
+ if (_typeStubInfo.RoutingStyle == SoapServiceRoutingStyle.SoapAction)
{
+ soapAction = request.Headers ["SOAPAction"];
if (soapAction == null) throw new SoapException ("Missing SOAPAction header", SoapException.ClientFaultCode);
- int i = soapAction.LastIndexOf ('/');
- methodName = soapAction.Substring (i + 1);
- methodNamespace = soapAction.Substring (0, i);
+ methodInfo = GetMethodFromAction (soapAction);
+ message.MethodStubInfo = methodInfo;
}
- else
+
+ // Execute the high priority global extensions. Do not try to execute the medium and
+ // low priority extensions because if the routing style is RequestElement we still
+ // don't have method information
+
+ _extensionChainHighPrio = SoapExtension.CreateExtensionChain (_typeStubInfo.SoapExtensions[0]);
+ stream = SoapExtension.ExecuteChainStream (_extensionChainHighPrio, stream);
+ SoapExtension.ExecuteProcessMessage (_extensionChainHighPrio, message, false);
+
+ // If the routing style is RequestElement, try to get the method name from the
+ // stream processed by the high priority extensions
+
+ if (_typeStubInfo.RoutingStyle == SoapServiceRoutingStyle.RequestElement)
{
- methodName = xmlReader.LocalName;
- methodNamespace = xmlReader.NamespaceURI;
+ MemoryStream mstream;
+
+ if (stream.CanSeek)
+ {
+ byte[] buffer = new byte [stream.Length];
+ for (int n=0; n<stream.Length;)
+ n += stream.Read (buffer, n, (int)stream.Length-n);
+ mstream = new MemoryStream (buffer);
+ }
+ else
+ {
+ byte[] buffer = new byte [500];
+ mstream = new MemoryStream ();
+
+ int len;
+ while ((len = stream.Read (buffer, 0, 500)) > 0)
+ mstream.Write (buffer, 0, len);
+ mstream.Position = 0;
+ }
+
+ soapAction = ReadActionFromRequestElement (new MemoryStream (mstream.GetBuffer ()), encoding);
+
+ stream = mstream;
+ methodInfo = GetMethodFromAction (soapAction);
+ message.MethodStubInfo = methodInfo;
}
- MethodStubInfo methodInfo = _typeStubInfo.GetMethod (methodName);
- if (methodInfo == null) throw new SoapException ("Method '" + methodName + "' not defined in the web service '" + _typeStubInfo.WebServiceName + "'", SoapException.ClientFaultCode);
+ // Whatever routing style we used, we should now have the method information.
+ // We can now notify the remaining extensions
+ if (methodInfo == null) throw new SoapException ("Method '" + soapAction + "' not defined in the web service '" + _typeStubInfo.WebServiceName + "'", SoapException.ClientFaultCode);
- object server = Activator.CreateInstance (_type);
- SoapServerMessage message = new SoapServerMessage (request, headers, methodInfo, server, stream);
+ _extensionChainMedPrio = SoapExtension.CreateExtensionChain (methodInfo.SoapExtensions);
+ _extensionChainLowPrio = SoapExtension.CreateExtensionChain (_typeStubInfo.SoapExtensions[1]);
- message.SetStage (SoapMessageStage.BeforeDeserialize);
- // TODO: Call extensions
+ stream = SoapExtension.ExecuteChainStream (_extensionChainMedPrio, stream);
+ stream = SoapExtension.ExecuteChainStream (_extensionChainLowPrio, stream);
+ SoapExtension.ExecuteProcessMessage (_extensionChainMedPrio, message, false);
+ SoapExtension.ExecuteProcessMessage (_extensionChainLowPrio, message, false);
+
+ // Deserialize the request
+
+ StreamReader reader = new StreamReader (stream, encoding, false);
+ XmlTextReader xmlReader = new XmlTextReader (reader);
try
{
- message.InParameters = (object []) methodInfo.RequestSerializer.Deserialize (xmlReader);
+ object content;\r
+ SoapHeaderCollection headers;\r
+ WebServiceHelper.ReadSoapMessage (xmlReader, _typeStubInfo, methodInfo.RequestSerializer, out content, out headers);\r
+ message.InParameters = (object []) content;
+ message.SetHeaders (headers);
}
catch (Exception ex)
{
throw new SoapException ("Could not deserialize Soap message", SoapException.ClientFaultCode, ex);
}
+ // Notify the extensions after deserialization
+
message.SetStage (SoapMessageStage.AfterDeserialize);
- // TODO: Call extensions
+ SoapExtension.ExecuteProcessMessage (_extensionChainHighPrio, message, false);
+ SoapExtension.ExecuteProcessMessage (_extensionChainMedPrio, message, false);
+ SoapExtension.ExecuteProcessMessage (_extensionChainLowPrio, message, false);
xmlReader.Close ();
}
}
+ MethodStubInfo GetMethodFromAction (string soapAction)
+ {
+ int i = soapAction.LastIndexOf ('/');
+ string methodName = soapAction.Substring (i + 1);
+ return _typeStubInfo.GetMethod (methodName);
+ }
+
+ string ReadActionFromRequestElement (Stream stream, Encoding encoding)
+ {
+ try
+ {
+ StreamReader reader = new StreamReader (stream, encoding, false);
+ XmlTextReader xmlReader = new XmlTextReader (reader);
+
+ xmlReader.MoveToContent ();
+ xmlReader.ReadStartElement ("Envelope", WebServiceHelper.SoapEnvelopeNamespace);
+
+ while (! (xmlReader.NodeType == XmlNodeType.Element && xmlReader.LocalName == "Body" && xmlReader.NamespaceURI == WebServiceHelper.SoapEnvelopeNamespace))
+ xmlReader.Skip ();
+
+ xmlReader.ReadStartElement ("Body", WebServiceHelper.SoapEnvelopeNamespace);
+ xmlReader.MoveToContent ();
+
+ if (xmlReader.NamespaceURI.EndsWith ("/")) return xmlReader.NamespaceURI + xmlReader.LocalName;
+ else return xmlReader.NamespaceURI + "/" + xmlReader.LocalName;
+ }
+ catch (Exception ex)
+ {
+ string errmsg = "The root element for the request could not be determined. ";
+ errmsg += "When RoutingStyle is set to RequestElement, SoapExtensions configured ";
+ errmsg += "via an attribute on the method cannot modify the request stream before it is read. ";
+ errmsg += "The extension must be configured via the SoapExtensionTypes element in web.config ";
+ errmsg += "or the request must arrive at the server as clear text.";
+ throw new SoapException (errmsg, SoapException.ServerFaultCode, ex);
+ }
+ }
+
void SerializeResponse (HttpResponse response, SoapServerMessage message)
{
MethodStubInfo methodInfo = message.MethodStubInfo;
Stream outStream = response.OutputStream;
using (outStream)
{
- response.ContentType = message.ContentType + "; charset=utf-8";
+ response.ContentType = "text/xml; charset=utf-8";
+
+ // While serializing, process extensions in reverse order
+
+ outStream = SoapExtension.ExecuteChainStream (_extensionChainHighPrio, outStream);
+ outStream = SoapExtension.ExecuteChainStream (_extensionChainMedPrio, outStream);
+ outStream = SoapExtension.ExecuteChainStream (_extensionChainLowPrio, outStream);
+
message.SetStage (SoapMessageStage.BeforeSerialize);
- // TODO: Call extensions
+ SoapExtension.ExecuteProcessMessage (_extensionChainLowPrio, message, true);
+ SoapExtension.ExecuteProcessMessage (_extensionChainMedPrio, message, true);
+ SoapExtension.ExecuteProcessMessage (_extensionChainHighPrio, message, true);
// What a waste of UTF8encoders, but it has to be thread safe.
XmlTextWriter xtw = new XmlTextWriter (outStream, new UTF8Encoding (false));
}
message.SetStage (SoapMessageStage.AfterSerialize);
- // TODO: Call extensions
+ SoapExtension.ExecuteProcessMessage (_extensionChainLowPrio, message, true);
+ SoapExtension.ExecuteProcessMessage (_extensionChainMedPrio, message, true);
+ SoapExtension.ExecuteProcessMessage (_extensionChainHighPrio, message, true);
- xtw.Flush ();
xtw.Close ();
}
}
SerializeResponse (context.Response, faultMessage);
return;
}
-
- SoapHeaderCollection ReadHeaders (XmlTextReader xmlReader)
- {
- SoapHeaderCollection headers = new SoapHeaderCollection ();
- while (! (xmlReader.NodeType == XmlNodeType.Element && xmlReader.LocalName == "Body" && xmlReader.NamespaceURI == WebServiceHelper.SoapEnvelopeNamespace))
- {
- if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.LocalName == "Header" && xmlReader.NamespaceURI == WebServiceHelper.SoapEnvelopeNamespace)
- {
- xmlReader.ReadStartElement ();
- xmlReader.MoveToContent ();
- XmlQualifiedName qname = new XmlQualifiedName (xmlReader.LocalName, xmlReader.NamespaceURI);
- XmlSerializer headerSerializer = _typeStubInfo.GetHeaderSerializer (qname);
- if (headerSerializer != null)
- {
- SoapHeader header = (SoapHeader) headerSerializer.Deserialize (xmlReader);
- headers.Add (header);
- }
- else
- {
- while (xmlReader.NodeType == XmlNodeType.EndElement)
- xmlReader.Skip (); // TODO: Check if the header has mustUnderstand=true
- xmlReader.Skip ();
- }
- }
- else
- xmlReader.Skip ();
- }
- return headers;
- }
}
}
internal HeaderInfo[] Headers;
+ internal SoapExtensionRuntimeConfig[] SoapExtensions;
+
//
// Constructor
//
XmlReflectionMember [] out_members = BuildResponseReflectionMembers (optional_ns);
XmlMembersMapping [] members = new XmlMembersMapping [2];
- try {
- if (use == SoapBindingUse.Literal) {
- members [0] = xmlImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, true);
- members [1] = xmlImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, true);
- }
- else {
- members [0] = soapImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, true, true);
- members [1] = soapImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, true, true);
- }
-
- XmlSerializer [] s = null;
- s = XmlSerializer.FromMappings (members);
- RequestSerializer = s [0];
- ResponseSerializer = s [1];
- } catch {
- Console.WriteLine ("Got exception while creating serializer");
- Console.WriteLine ("Method name: " + RequestName + " parameters are:");
- for (int i = 0; i < in_members.Length; i++) {
- Console.WriteLine (" {0}: {1} {2}", i, in_members [i].MemberName, in_members [i].MemberType);
- }
-
- Console.WriteLine ("Output parameters are:");
- for (int i = 0; i < out_members.Length; i++) {
- Console.WriteLine (" {0}: {1} {2}", i, out_members [i].MemberName, out_members [i].MemberType);
- }
- throw;
+ if (use == SoapBindingUse.Literal) {
+ members [0] = xmlImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, true);
+ members [1] = xmlImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, true);
}
+ else {
+ members [0] = soapImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, true, true);
+ members [1] = soapImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, true, true);
+ }
+
+ XmlSerializer [] s = null;
+ s = XmlSerializer.FromMappings (members);
+ RequestSerializer = s [0];
+ ResponseSerializer = s [1];
o = source.GetCustomAttributes (typeof (SoapHeaderAttribute));
Headers = new HeaderInfo[o.Length];
Headers [i] = new HeaderInfo (mems[0], att);
parent.RegisterHeaderType (headerType);
}
+
+ SoapExtensions = SoapExtension.GetMethodExtensions (source);
}
static internal MethodStubInfo Create (TypeStubInfo parent, LogicalMethodInfo lmi, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter)
if (Member is PropertyInfo) ((PropertyInfo)Member).SetValue (ob, value, null);
else ((FieldInfo)Member).SetValue (ob, value);
}
+
+ public SoapHeaderDirection Direction
+ {
+ get { return AttributeInfo.Direction; }
+ }
}
internal class Fault
internal string WebServiceName;
internal string WebServiceNamespace;
internal XmlSerializer FaultSerializer;
+ internal SoapExtensionRuntimeConfig[][] SoapExtensions;
void GetTypeAttributes (Type t)
{
}
}
FaultSerializer = new XmlSerializer (typeof(Fault));
+ SoapExtensions = SoapExtension.GetTypeExtensions (t);
}
//
if (s != null) return;
XmlReflectionImporter ri = new XmlReflectionImporter ();
- XmlTypeMapping tm = ri.ImportTypeMapping (type);
- s = new XmlSerializer (type);
+ XmlTypeMapping tm = ri.ImportTypeMapping (type, WebServiceAttribute.DefaultNamespace);
+ s = new XmlSerializer (tm);
header_serializers [type] = s;
header_serializers_byname [new XmlQualifiedName (tm.ElementName, tm.Namespace)] = s;
[MonoTODO ("Figure out what this class does.")]\r
internal abstract class ServerProtocol {\r
\r
+ HttpContext _context;\r
+\r
#region Constructors\r
\r
+ internal ServerProtocol (HttpContext context)\r
+ {\r
+ _context = context;\r
+ }\r
+\r
protected ServerProtocol ()\r
{\r
throw new NotImplementedException ();\r
\r
#region Properties\r
\r
- [MonoTODO]\r
public HttpContext Context {\r
- get { throw new NotImplementedException (); }\r
+ get { return _context; }\r
}\r
\r
public abstract bool IsOneWay {\r
get { throw new NotImplementedException (); }\r
}\r
\r
- [MonoTODO]\r
public HttpRequest Request {\r
- get { throw new NotImplementedException (); }\r
+ get { return _context.Request; }\r
}\r
\r
- [MonoTODO]\r
public HttpResponse Response {\r
- get { throw new NotImplementedException (); }\r
+ get { return _context.Response; }\r
}\r
\r
#endregion\r
this.client_method = client_method;\r
this.url = url;\r
Parameters = parameters;\r
-\r
- foreach (HeaderInfo hi in msi.Headers) {\r
- SoapHeader headerVal = hi.GetHeaderValue (client) as SoapHeader;\r
- if (headerVal != null)\r
- Headers.Add (headerVal);\r
- }\r
}\r
\r
#endregion \r
//\r
\r
using System.IO;\r
+using System.Collections;\r
+using System.Web.Services.Configuration;\r
\r
namespace System.Web.Services.Protocols {\r
public abstract class SoapExtension {\r
\r
#region Constructors\r
\r
- [MonoTODO]\r
protected SoapExtension ()\r
{\r
- throw new NotImplementedException ();\r
}\r
\r
#endregion // Constructors\r
public abstract void Initialize (object initializer);\r
public abstract void ProcessMessage (SoapMessage message);\r
\r
+\r
+ static ArrayList[] globalExtensions;\r
+\r
+ internal static SoapExtension[] CreateExtensionChain (SoapExtensionRuntimeConfig[] extensionConfigs)\r
+ {\r
+ if (extensionConfigs == null) return null;\r
+ SoapExtension[] res = new SoapExtension [extensionConfigs.Length];\r
+ CreateExtensionChain (extensionConfigs, res, 0);\r
+ return res;\r
+ }\r
+\r
+ internal static SoapExtension[] CreateExtensionChain (SoapExtensionRuntimeConfig[] hiPrioExts, SoapExtensionRuntimeConfig[] medPrioExts, SoapExtensionRuntimeConfig[] lowPrioExts)\r
+ {\r
+ int len = 0;\r
+ if (hiPrioExts != null) len += hiPrioExts.Length;\r
+ if (medPrioExts != null) len += medPrioExts.Length;\r
+ if (lowPrioExts != null) len += lowPrioExts.Length;\r
+ if (len == 0) return null;\r
+\r
+ SoapExtension[] res = new SoapExtension [len];\r
+ int pos = 0;\r
+ if (hiPrioExts != null) pos = CreateExtensionChain (hiPrioExts, res, pos);\r
+ if (medPrioExts != null) pos = CreateExtensionChain (medPrioExts, res, pos);\r
+ if (lowPrioExts != null) pos = CreateExtensionChain (lowPrioExts, res, pos);\r
+ return res;\r
+ }\r
+\r
+ static int CreateExtensionChain (SoapExtensionRuntimeConfig[] extensionConfigs, SoapExtension[] destArray, int pos)\r
+ {\r
+ for (int n=0; n<extensionConfigs.Length; n++)\r
+ {\r
+ SoapExtensionRuntimeConfig econf = extensionConfigs [n];\r
+ SoapExtension ext = (SoapExtension) Activator.CreateInstance (econf.Type);\r
+ ext.Initialize (econf.InitializationInfo);\r
+ destArray [pos++] = ext;\r
+ }\r
+ return pos;\r
+ }\r
+\r
+ static void InitializeGlobalExtensions ()\r
+ {\r
+ globalExtensions = new ArrayList[2];\r
+ \r
+ ArrayList exts = WSConfig.Instance.ExtensionTypes;\r
+ if (exts == null) return;\r
+\r
+ foreach (WSExtensionConfig econf in exts)\r
+ {\r
+ if (globalExtensions [(int)econf.Group] == null) globalExtensions [(int)econf.Group] = new ArrayList ();\r
+ ArrayList destList = globalExtensions [(int) econf.Group];\r
+ bool added = false;\r
+ for (int n=0; n<destList.Count && !added; n++)\r
+ if (((WSExtensionConfig)destList [n]).Priority > econf.Priority) {\r
+ destList.Insert (n, econf);\r
+ added = true;\r
+ }\r
+ if (!added) destList.Add (econf);\r
+ }\r
+ }\r
+\r
+ internal static SoapExtensionRuntimeConfig[][] GetTypeExtensions (Type serviceType)\r
+ {\r
+ if (globalExtensions == null) InitializeGlobalExtensions();\r
+ \r
+ SoapExtensionRuntimeConfig[][] exts = new SoapExtensionRuntimeConfig[2][];\r
+\r
+ for (int group = 0; group < 2; group++)\r
+ {\r
+ ArrayList globList = globalExtensions[group];\r
+ if (globList == null) continue;\r
+ exts [group] = new SoapExtensionRuntimeConfig [globList.Count];\r
+ for (int n=0; n<globList.Count; n++)\r
+ {\r
+ WSExtensionConfig econf = (WSExtensionConfig) globList [n];\r
+ SoapExtensionRuntimeConfig typeconf = new SoapExtensionRuntimeConfig ();\r
+ typeconf.Type = econf.Type;\r
+ SoapExtension ext = (SoapExtension) Activator.CreateInstance (econf.Type);\r
+ typeconf.InitializationInfo = ext.GetInitializer (serviceType);\r
+ exts [group][n] = typeconf;\r
+ }\r
+ }\r
+ return exts;\r
+ }\r
+\r
+ internal static SoapExtensionRuntimeConfig[] GetMethodExtensions (LogicalMethodInfo method)\r
+ {\r
+ object[] ats = method.GetCustomAttributes (typeof (SoapExtensionAttribute));\r
+ SoapExtensionRuntimeConfig[] exts = new SoapExtensionRuntimeConfig [ats.Length];\r
+ int[] priorities = new int[ats.Length];\r
+\r
+ for (int n=0; n<ats.Length; n++)\r
+ {\r
+ SoapExtensionAttribute at = (SoapExtensionAttribute) ats[n];\r
+ SoapExtensionRuntimeConfig econf = new SoapExtensionRuntimeConfig ();\r
+ econf.Type = at.ExtensionType;\r
+ priorities [n] = at.Priority;\r
+ SoapExtension ext = (SoapExtension) Activator.CreateInstance (econf.Type);\r
+ econf.InitializationInfo = ext.GetInitializer (method, at);\r
+ exts [n] = econf;\r
+ }\r
+ Array.Sort (priorities, exts);\r
+ return exts;\r
+ }\r
+\r
+ public static Stream ExecuteChainStream (SoapExtension[] extensions, Stream stream)\r
+ {\r
+ if (extensions == null) return stream;\r
+\r
+ Stream newStream = stream;\r
+ foreach (SoapExtension ext in extensions)\r
+ newStream = ext.ChainStream (newStream);\r
+ return newStream;\r
+ }\r
+\r
+ public static void ExecuteProcessMessage(SoapExtension[] extensions, SoapMessage message, bool inverseOrder)\r
+ {\r
+ if (extensions == null) return;\r
+\r
+ if (inverseOrder)\r
+ {\r
+ for (int n = extensions.Length-1; n >= 0; n--)\r
+ extensions[n].ProcessMessage (message);\r
+ }\r
+ else\r
+ {\r
+ for (int n = 0; n < extensions.Length; n++)\r
+ extensions[n].ProcessMessage (message);\r
+ }\r
+ }
+\r
#endregion // Methods\r
}\r
+\r
+ internal class SoapExtensionRuntimeConfig\r
+ {\r
+ public Type Type;\r
+ public int Priority;\r
+ public object InitializationInfo;\r
+ }\r
}\r
using System.Web.Services.Description;\r
using System.Xml.Serialization;\r
using System.Xml.Schema;\r
+using System.Collections;\r
\r
namespace System.Web.Services.Protocols {\r
public class SoapHttpClientProtocol : HttpWebClientProtocol {\r
}\r
}\r
\r
- void SendRequest (WebRequest request, SoapClientMessage message)\r
+ void SendRequest (WebRequest request, SoapClientMessage message, SoapExtension[] extensions)\r
{\r
+ message.CollectHeaders (this, message.MethodStubInfo.Headers, SoapHeaderDirection.In);\r
+\r
request.Method = "POST";\r
WebHeaderCollection headers = request.Headers;\r
headers.Add ("SOAPAction", message.Action);\r
\r
request.ContentType = message.ContentType + "; charset=utf-8";\r
\r
- using (Stream s = request.GetRequestStream ()){\r
+ Stream s = request.GetRequestStream ();\r
+ using (s) {\r
+\r
+ if (extensions != null) {\r
+ s = SoapExtension.ExecuteChainStream (extensions, s);\r
+ message.SetStage (SoapMessageStage.BeforeSerialize);\r
+ SoapExtension.ExecuteProcessMessage (extensions, message, true);
+ }
\r
// What a waste of UTF8encoders, but it has to be thread safe.\r
- \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
- \r
+\r
+ if (extensions != null) {\r
+ message.SetStage (SoapMessageStage.AfterSerialize);\r
+ SoapExtension.ExecuteProcessMessage (extensions, message, true);
+ }
+\r
xtw.Flush ();\r
xtw.Close ();\r
}\r
// TODO:\r
// Handle other web responses (multi-output?)\r
// \r
- object [] ReceiveResponse (WebResponse response, SoapClientMessage message)\r
-\r
+ object [] ReceiveResponse (WebResponse response, SoapClientMessage message, SoapExtension[] extensions)\r
{\r
HttpWebResponse http_response = (HttpWebResponse) response;\r
HttpStatusCode code = http_response.StatusCode;\r
\r
//\r
// Remove optional encoding\r
-\r
//\r
Encoding encoding = WebServiceHelper.GetContentEncoding (response.ContentType);\r
\r
Stream stream = response.GetResponseStream ();\r
+\r
+ if (extensions != null) {\r
+ stream = SoapExtension.ExecuteChainStream (extensions, stream);\r
+ message.SetStage (SoapMessageStage.BeforeDeserialize);\r
+ SoapExtension.ExecuteProcessMessage (extensions, message, false);
+ }
+ \r
+ // Deserialize the response\r
+\r
StreamReader reader = new StreamReader (stream, encoding, false);\r
XmlTextReader xml_reader = new XmlTextReader (reader);\r
\r
- xml_reader.MoveToContent ();\r
- xml_reader.ReadStartElement ("Envelope", WebServiceHelper.SoapEnvelopeNamespace);\r
- xml_reader.MoveToContent ();\r
- xml_reader.ReadStartElement ("Body", WebServiceHelper.SoapEnvelopeNamespace);\r
+ bool isSuccessful = (code != HttpStatusCode.InternalServerError);\r
+ SoapHeaderCollection headers;\r
+ object content;\r
\r
- if (code != HttpStatusCode.InternalServerError)\r
- {\r
- object [] ret = (object []) msi.ResponseSerializer.Deserialize (xml_reader);\r
- return (object []) ret;\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
- {\r
- Fault fault = (Fault) type_info.FaultSerializer.Deserialize (xml_reader);\r
- throw new SoapException (fault.faultstring, fault.faultcode, fault.faultactor, fault.detail);\r
+ else {\r
+ WebServiceHelper.ReadSoapMessage (xml_reader, type_info, type_info.FaultSerializer, out content, out headers);\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
+ message.SetHeaders (headers);\r
+ message.UpdateHeaderValues (this, message.MethodStubInfo.Headers);\r
+\r
+ if (extensions != null) {\r
+ message.SetStage (SoapMessageStage.AfterDeserialize);\r
+ SoapExtension.ExecuteProcessMessage (extensions, message, false);
+ }
+\r
+ if (isSuccessful)\r
+ return message.OutParameters;\r
+ else\r
+ throw message.Exception;\r
}\r
\r
protected object[] Invoke (string method_name, object[] parameters)\r
{\r
MethodStubInfo msi = type_info.GetMethod (method_name);\r
-\r
+ \r
SoapClientMessage message = new SoapClientMessage (\r
this, msi, Url, parameters);\r
\r
+ SoapExtension[] extensions = SoapExtension.CreateExtensionChain (type_info.SoapExtensions[0], msi.SoapExtensions, type_info.SoapExtensions[1]);\r
+\r
WebResponse response;\r
try\r
{\r
WebRequest request = GetWebRequest (uri);\r
- SendRequest (request, message);\r
+ SendRequest (request, message, extensions);\r
response = GetWebResponse (request);\r
}\r
catch (WebException ex)\r
throw ex;\r
}\r
\r
- return ReceiveResponse (response, message);\r
+ return ReceiveResponse (response, message, extensions);\r
}\r
\r
#endregion // Methods\r
headers = new SoapHeaderCollection ();\r
}\r
\r
- internal SoapMessage (Stream stream, SoapHeaderCollection headers)\r
+ internal SoapMessage (Stream stream)\r
{\r
- this.headers = headers;\r
this.stream = stream;\r
}\r
\r
else return outParameters [0];\r
}\r
\r
+ internal void SetHeaders (SoapHeaderCollection headers)\r
+ {\r
+ this.headers = headers;\r
+ }\r
+\r
+ internal void SetException (SoapException ex)\r
+ {\r
+ exception = ex;\r
+ }\r
+\r
+ internal void CollectHeaders (object target, HeaderInfo[] headers, SoapHeaderDirection direction)\r
+ {\r
+ Headers.Clear ();\r
+ foreach (HeaderInfo hi in headers) \r
+ {\r
+ if ((hi.Direction & direction) != 0) \r
+ {\r
+ SoapHeader headerVal = hi.GetHeaderValue (target) as SoapHeader;\r
+ if (headerVal != null)\r
+ Headers.Add (headerVal);\r
+ }\r
+ }\r
+ }\r
+\r
+ internal void UpdateHeaderValues (object target, HeaderInfo[] headersInfo)\r
+ {\r
+ foreach (SoapHeader header in Headers)\r
+ {\r
+ HeaderInfo hinfo = FindHeader (headersInfo, header.GetType ());\r
+ if (hinfo != null)\r
+ hinfo.SetHeaderValue (target, header);\r
+ else\r
+ if (header.MustUnderstand)\r
+ throw new SoapHeaderException ("Unknown header", SoapException.MustUnderstandFaultCode);\r
+ header.DidUnderstand = false;\r
+ }\r
+ }\r
+\r
+ HeaderInfo FindHeader (HeaderInfo[] headersInfo, Type headerType)\r
+ {\r
+ foreach (HeaderInfo headerInfo in headersInfo)
+ if (headerInfo.HeaderType == headerType) return headerInfo;
+ return null;
+ }\r
+\r
#endregion // Methods\r
}\r
}\r
\r
#region Constructors\r
\r
- internal SoapServerMessage (HttpRequest request, SoapHeaderCollection headers, MethodStubInfo stubInfo, object server, Stream stream)\r
- : base (stream, headers)\r
+ internal SoapServerMessage (HttpRequest request, object server, Stream stream)\r
+ : base (stream, null)\r
{\r
this.action = request.Headers ["SOAPAction"];\r
- this.stubInfo = stubInfo;\r
this.server = server;\r
this.url = request.Url.ToString();\r
}\r
\r
internal MethodStubInfo MethodStubInfo {\r
get { return stubInfo; }\r
+ set { stubInfo = value; }\r
}\r
\r
public override bool OneWay {\r
MethodStubInfo methodInfo = requestMessage.MethodStubInfo;\r
\r
// Assign header values to web service members\r
- foreach (SoapHeader header in requestMessage.Headers)\r
- {\r
- HeaderInfo hinfo = methodInfo.GetHeaderInfo (header.GetType ());\r
- if (hinfo != null)\r
- hinfo.SetHeaderValue (requestMessage.Server, header);\r
- else\r
- if (header.MustUnderstand)\r
- throw new SoapHeaderException ("Unknown header", SoapException.MustUnderstandFaultCode);\r
- header.DidUnderstand = false;\r
- }\r
+\r
+ requestMessage.UpdateHeaderValues (requestMessage.Server, methodInfo.Headers);\r
\r
// Fill an array with the input parameters at the right position\r
- \r
\r
object[] parameters = new object[methodInfo.MethodInfo.Parameters.Length];\r
ParameterInfo[] inParams = methodInfo.MethodInfo.InParameters;\r
parameters [inParams[n].Position - 1] = requestMessage.InParameters [n];\r
\r
// Invoke the method\r
- \r
- object[] results = methodInfo.MethodInfo.Invoke (requestMessage.Server, parameters);\r
- requestMessage.OutParameters = results;\r
+\r
+ try\r
+ {\r
+ object[] results = methodInfo.MethodInfo.Invoke (requestMessage.Server, parameters);\r
+ requestMessage.OutParameters = results;\r
+ }\r
+ catch (TargetInvocationException ex)\r
+ {\r
+ throw ex.InnerException;\r
+ }\r
\r
// Check that headers with MustUnderstand flag have been understood\r
\r
throw new SoapHeaderException ("Header not understood: " + header.GetType(), SoapException.MustUnderstandFaultCode);\r
}\r
\r
+ // Collect headers that must be sent to the client\r
+ requestMessage.CollectHeaders (requestMessage.Server, methodInfo.Headers, SoapHeaderDirection.Out);\r
+\r
return requestMessage;\r
}\r
\r
public IHttpHandler GetHandler (HttpContext context, string verb, string url, string filePath)
{
- Type type = WebServiceParser.GetCompiledType (filePath, context);
+ Type type = WebServiceParser.GetCompiledType (filePath, context);
WSProtocol protocol = GuessProtocol (context, verb);
IHttpHandler handler = null;
- if (true /*WSConfig.IsSupported (protocol)*/) {
+ if (WSConfig.IsSupported (protocol)) {
switch (protocol) {
case WSProtocol.HttpSoap:
handler = new HttpSoapWebServiceHandler (type);
xtw.WriteEndElement ();
xtw.WriteEndElement ();
+ xtw.Flush ();
+ }
+
+ public static void ReadSoapMessage (XmlTextReader xmlReader, TypeStubInfo typeStubInfo, XmlSerializer bodySerializer, out object body, out SoapHeaderCollection headers)
+ {
+ xmlReader.MoveToContent ();\r
+ xmlReader.ReadStartElement ("Envelope", WebServiceHelper.SoapEnvelopeNamespace);\r
+\r
+ headers = ReadHeaders (typeStubInfo, xmlReader);\r
+\r
+ xmlReader.MoveToContent ();\r
+ xmlReader.ReadStartElement ("Body", WebServiceHelper.SoapEnvelopeNamespace);\r
+ xmlReader.MoveToContent ();\r
+\r
+ body = bodySerializer.Deserialize (xmlReader);\r
+ }
+
+ static SoapHeaderCollection ReadHeaders (TypeStubInfo typeStubInfo, XmlTextReader xmlReader)
+ {
+ SoapHeaderCollection headers = new SoapHeaderCollection ();
+ while (! (xmlReader.NodeType == XmlNodeType.Element && xmlReader.LocalName == "Body" && xmlReader.NamespaceURI == WebServiceHelper.SoapEnvelopeNamespace))
+ {
+ if (xmlReader.NodeType == XmlNodeType.Element && xmlReader.LocalName == "Header" && xmlReader.NamespaceURI == WebServiceHelper.SoapEnvelopeNamespace)
+ {
+ xmlReader.ReadStartElement ();
+ xmlReader.MoveToContent ();
+ XmlQualifiedName qname = new XmlQualifiedName (xmlReader.LocalName, xmlReader.NamespaceURI);
+ XmlSerializer headerSerializer = typeStubInfo.GetHeaderSerializer (qname);
+ if (headerSerializer != null)
+ {
+ SoapHeader header = (SoapHeader) headerSerializer.Deserialize (xmlReader);
+ headers.Add (header);
+ }
+ else
+ {
+ while (xmlReader.NodeType == XmlNodeType.EndElement)
+ xmlReader.Skip (); // TODO: Check if the header has mustUnderstand=true
+ xmlReader.Skip ();
+ }
+ }
+ else
+ xmlReader.Skip ();
+ }
+ return headers;
}
}
}