* SoapHttpClientProtocol.cs, HttpSoapWebServiceHandler.cs, Methods.cs:
authorLluis Sanchez <lluis@novell.com>
Wed, 9 Jul 2003 16:23:31 +0000 (16:23 -0000)
committerLluis Sanchez <lluis@novell.com>
Wed, 9 Jul 2003 16:23:31 +0000 (16:23 -0000)
  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.

svn path=/trunk/mcs/; revision=16057

12 files changed:
mcs/class/System.Web.Services/System.Web.Services.Protocols/ChangeLog
mcs/class/System.Web.Services/System.Web.Services.Protocols/HttpSoapWebServiceHandler.cs
mcs/class/System.Web.Services/System.Web.Services.Protocols/Methods.cs
mcs/class/System.Web.Services/System.Web.Services.Protocols/ServerProtocol.cs
mcs/class/System.Web.Services/System.Web.Services.Protocols/SoapClientMessage.cs
mcs/class/System.Web.Services/System.Web.Services.Protocols/SoapExtension.cs
mcs/class/System.Web.Services/System.Web.Services.Protocols/SoapHttpClientProtocol.cs
mcs/class/System.Web.Services/System.Web.Services.Protocols/SoapMessage.cs
mcs/class/System.Web.Services/System.Web.Services.Protocols/SoapServerMessage.cs
mcs/class/System.Web.Services/System.Web.Services.Protocols/WebServiceHandler.cs
mcs/class/System.Web.Services/System.Web.Services.Protocols/WebServiceHandlerFactory.cs
mcs/class/System.Web.Services/System.Web.Services.Protocols/WebServiceHelper.cs

index 20762e5c80224c187915e55ca4082067f67eced8..f1ba6c75dcf5ccc18d17c5b3770c16f2fc35d1d0 100644 (file)
@@ -1,3 +1,17 @@
+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,
index 069cf4f0f5daecabf026e7d1b30369821db5cb2b..22a62b684fc6cf0c41a64d1b1d5bbc4b116dbb95 100755 (executable)
@@ -20,6 +20,9 @@ namespace System.Web.Services.Protocols
        {
                Type _type;
                TypeStubInfo _typeStubInfo;
+               SoapExtension[] _extensionChainHighPrio;
+               SoapExtension[] _extensionChainMedPrio;
+               SoapExtension[] _extensionChainLowPrio;
 
                public HttpSoapWebServiceHandler (Type type)
                {
@@ -47,8 +50,6 @@ namespace System.Web.Services.Protocols
                        {
                                SerializeFault (context, requestMessage, ex);
                                return;
-
-
                        }
                }
 
@@ -58,57 +59,102 @@ namespace System.Web.Services.Protocols
 
                        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 ();
 
@@ -116,6 +162,43 @@ namespace System.Web.Services.Protocols
                        }
                }
 
+               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;
@@ -123,9 +206,18 @@ namespace System.Web.Services.Protocols
                        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));
@@ -140,9 +232,10 @@ namespace System.Web.Services.Protocols
                                }
 
                                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 ();
                        }
                }
@@ -165,34 +258,5 @@ namespace System.Web.Services.Protocols
                        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;
-               }
        }
 }
index 3b3d438877c080ca097a4fa60a7a8e1eb0b6d6f6..ee47b71c5b8e3057e7e11a5baa67cbb1d522909b 100644 (file)
@@ -54,6 +54,8 @@ namespace System.Web.Services.Protocols {
 
                internal HeaderInfo[] Headers;
 
+               internal SoapExtensionRuntimeConfig[] SoapExtensions;
+
                //
                // Constructor
                //
@@ -138,34 +140,20 @@ namespace System.Web.Services.Protocols {
                        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];
@@ -178,6 +166,8 @@ namespace System.Web.Services.Protocols {
                                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)
@@ -293,6 +283,11 @@ namespace System.Web.Services.Protocols {
                        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
@@ -330,6 +325,7 @@ namespace System.Web.Services.Protocols {
                internal string                  WebServiceName;
                internal string                  WebServiceNamespace;
                internal XmlSerializer           FaultSerializer;
+               internal SoapExtensionRuntimeConfig[][] SoapExtensions;
 
                void GetTypeAttributes (Type t)
                {
@@ -373,6 +369,7 @@ namespace System.Web.Services.Protocols {
                                }
                        }
                        FaultSerializer = new XmlSerializer (typeof(Fault));
+                       SoapExtensions = SoapExtension.GetTypeExtensions (t);
                }
 
                //
@@ -415,8 +412,8 @@ namespace System.Web.Services.Protocols {
                        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;
index 5c778125aff5b7ab5f635b91ff2466a7ba7f94d3..a740c860743511179321ae5db84e884df76eb67c 100644 (file)
@@ -15,8 +15,15 @@ namespace System.Web.Services.Protocols {
        [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
@@ -26,9 +33,8 @@ namespace System.Web.Services.Protocols {
 \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
@@ -44,14 +50,12 @@ namespace System.Web.Services.Protocols {
                        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
index bfc3e97332893b5f76d77ada48b922ad3a1d666c..67580c4882730e745755fc78c5c3ca2aa6feec69 100644 (file)
@@ -40,12 +40,6 @@ namespace System.Web.Services.Protocols {
                        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
index 48f91cd38db2db740730a12deeaccbe0ca653912..57aea4aac74a3e1218e9ba297b430a071528ed7b 100644 (file)
@@ -8,6 +8,8 @@
 //\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
@@ -20,10 +22,8 @@ namespace System.Web.Services.Protocols {
 \r
                #region Constructors\r
 \r
-               [MonoTODO]\r
                protected SoapExtension ()\r
                {\r
-                       throw new NotImplementedException ();\r
                }\r
 \r
                #endregion // Constructors\r
@@ -41,6 +41,143 @@ namespace System.Web.Services.Protocols {
                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
index fe18ab399140a8bf91dfcc77765dede4b12e016d..2e9ef3f9fd0fbe090355fa790d1162c3ffb976cf 100644 (file)
@@ -22,6 +22,7 @@ using System.Runtime.CompilerServices;
 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
@@ -74,23 +75,36 @@ namespace System.Web.Services.Protocols {
                        }\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
@@ -101,8 +115,7 @@ namespace System.Web.Services.Protocols {
                // 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
@@ -113,43 +126,65 @@ namespace System.Web.Services.Protocols {
 \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
@@ -160,7 +195,7 @@ namespace System.Web.Services.Protocols {
                                        throw ex;\r
                        }\r
 \r
-                       return ReceiveResponse (response, message);\r
+                       return ReceiveResponse (response, message, extensions);\r
                }\r
 \r
                #endregion // Methods\r
index 26cca826cea4a8feea0b62a20d19faf16d23c1e2..ba0c8ff1eaa349161a8a9a4f8b9c9fcbdb8b3a90 100644 (file)
@@ -36,9 +36,8 @@ namespace System.Web.Services.Protocols {
                        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
@@ -140,6 +139,51 @@ namespace System.Web.Services.Protocols {
                        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
index f15cf9d66ce0e2943d7bda436eb7fe249fddc136..43c09f176a96b40650eaa0430549501708162c2c 100644 (file)
@@ -26,11 +26,10 @@ namespace System.Web.Services.Protocols {
 \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
@@ -58,6 +57,7 @@ namespace System.Web.Services.Protocols {
 \r
                internal MethodStubInfo MethodStubInfo {\r
                        get { return stubInfo; }\r
+                       set { stubInfo = value; }\r
                }\r
 \r
                public override bool OneWay {\r
index a58727162a40adb6c1496f329ffa013cef771a5f..8e9543ad54ec0b46e9e66fba4493a590e67954d7 100644 (file)
@@ -47,19 +47,10 @@ namespace System.Web.Services.Protocols {
                        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
@@ -67,9 +58,16 @@ namespace System.Web.Services.Protocols {
                                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
@@ -79,6 +77,9 @@ namespace System.Web.Services.Protocols {
                                        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
index c510833c3f6ea0f28e7fa724b20ac9cbcd4dc9f4..91d0ec9d27198dd2f31254a4687f14f0e70e61fc 100644 (file)
@@ -44,12 +44,12 @@ namespace System.Web.Services.Protocols
 
                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);
index 21b00601c7ec92eb19530b932c86bdcc6a0423c2..5887d2fcbd4a16429bedb6ce7079b91a87a360b8 100755 (executable)
@@ -78,6 +78,50 @@ namespace System.Web.Services.Protocols
 
                        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;
                }
        }
 }