2 // Methods.cs: Information about a method and its mapping to a SOAP web service.
7 // (C) 2003 Ximian, Inc.
13 using System.Reflection;
14 using System.Collections;
15 using System.Xml.Serialization;
16 using System.Web.Services;
17 using System.Web.Services.Description;
19 namespace System.Web.Services.Protocols {
22 // This class represents all the information we extract from a MethodInfo
23 // in the SoapHttpClientProtocol derivative stub class
25 internal class MethodStubInfo {
26 internal LogicalMethodInfo MethodInfo;
28 // The name used bythe stub class to reference this method.
31 internal string Action;
32 internal string Binding;
34 // The name/namespace of the request
35 internal string RequestName;
36 internal string RequestNamespace;
38 // The name/namespace of the response.
39 internal string ResponseName;
40 internal string ResponseNamespace;
43 internal SoapParameterStyle ParameterStyle;
45 internal XmlSerializer RequestSerializer;
46 internal XmlSerializer ResponseSerializer;
51 MethodStubInfo (TypeStubInfo parent, LogicalMethodInfo source, object kind, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter)
55 XmlElementAttribute optional_ns = null;
58 if (kind is SoapDocumentMethodAttribute){
59 SoapDocumentMethodAttribute dma = (SoapDocumentMethodAttribute) kind;
62 if (use == SoapBindingUse.Default)
66 Binding = dma.Binding;
67 RequestName = dma.RequestElementName;
68 RequestNamespace = dma.RequestNamespace;
69 ResponseName = dma.ResponseElementName;
70 ResponseNamespace = dma.ResponseNamespace;
71 ParameterStyle = dma.ParameterStyle;
72 if (ParameterStyle == SoapParameterStyle.Default)
73 ParameterStyle = parent.ParameterStyle;
76 SoapRpcMethodAttribute rma = (SoapRpcMethodAttribute) kind;
77 use = SoapBindingUse.Encoded; // RPC always use encoded
80 Binding = rma.Binding;
81 RequestName = rma.RequestElementName;
82 RequestNamespace = rma.RequestNamespace;
83 ResponseNamespace = rma.ResponseNamespace;
84 ResponseName = rma.ResponseElementName;
87 // For RPC calls, make all arguments be part of the empty namespace
88 optional_ns = new XmlElementAttribute ();
89 optional_ns.Namespace = "";
92 Binding = parent.BindingName;
93 if (RequestName == "")
94 RequestName = source.Name;
97 if (source.ReturnType != typeof (void))
98 throw new Exception ("OneWay methods should not have a return value");
99 if (source.OutParameters.Length != 0)
100 throw new Exception ("OneWay methods should not have out/ref parameters");
103 object [] o = source.GetCustomAttributes (typeof (WebMethodAttribute));
105 WebMethodAttribute wma = (WebMethodAttribute) o [0];
107 Name = wma.MessageName;
113 if (ResponseName == "")
114 ResponseName = Name + "Response";
116 XmlReflectionMember [] in_members = BuildRequestReflectionMembers (optional_ns);
117 XmlReflectionMember [] out_members = BuildResponseReflectionMembers (optional_ns);
119 XmlMembersMapping [] members = new XmlMembersMapping [2];
121 if (use == SoapBindingUse.Literal) {
122 members [0] = xmlImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, true);
123 members [1] = xmlImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, true);
126 members [0] = soapImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, true, true);
127 members [1] = soapImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, true, true);
130 XmlSerializer [] s = null;
131 s = XmlSerializer.FromMappings (members);
132 RequestSerializer = s [0];
133 ResponseSerializer = s [1];
135 Console.WriteLine ("Got exception while creating serializer");
136 Console.WriteLine ("Method name: " + RequestName + " parameters are:");
138 for (int i = 0; i < in_members.Length; i++) {
139 Console.WriteLine (" {0}: {1} {2}", i, in_members [i].MemberName, in_members [i].MemberType);
142 Console.WriteLine ("Output parameters are:");
143 for (int i = 0; i < out_members.Length; i++) {
144 Console.WriteLine (" {0}: {1} {2}", i, out_members [i].MemberName, out_members [i].MemberType);
148 ResponseSerializer.UnknownNode += new XmlNodeEventHandler (e);
\r
151 static internal MethodStubInfo Create (TypeStubInfo parent, LogicalMethodInfo lmi, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter)
153 object [] o = lmi.GetCustomAttributes (typeof (SoapDocumentMethodAttribute));
155 o = lmi.GetCustomAttributes (typeof (SoapRpcMethodAttribute));
158 return new MethodStubInfo (parent, lmi, o [0], xmlImporter, soapImporter);
160 return new MethodStubInfo (parent, lmi, o [0], xmlImporter, soapImporter);
163 XmlReflectionMember [] BuildRequestReflectionMembers (XmlElementAttribute optional_ns)
165 ParameterInfo [] input = MethodInfo.InParameters;
166 XmlReflectionMember [] in_members = new XmlReflectionMember [input.Length];
168 for (int i = 0; i < input.Length; i++)
\r
170 XmlReflectionMember m = new XmlReflectionMember ();
171 m.IsReturnValue = false;
172 m.MemberName = input [i].Name;
173 m.MemberType = input [i].ParameterType;
175 m.XmlAttributes = new XmlAttributes (input[i]);
176 m.SoapAttributes = new SoapAttributes (input[i]);
178 if (m.MemberType.IsByRef)
179 m.MemberType = m.MemberType.GetElementType ();
180 if (optional_ns != null)
181 m.XmlAttributes.XmlElements.Add (optional_ns);
187 XmlReflectionMember [] BuildResponseReflectionMembers (XmlElementAttribute optional_ns)
189 ParameterInfo [] output = MethodInfo.OutParameters;
190 bool has_return_value = !(OneWay || MethodInfo.ReturnType == typeof (void));
191 XmlReflectionMember [] out_members = new XmlReflectionMember [(has_return_value ? 1 : 0) + output.Length];
192 XmlReflectionMember m;
195 if (has_return_value)
\r
197 m = new XmlReflectionMember ();
198 m.IsReturnValue = true;
199 m.MemberName = RequestName + "Result";
200 m.MemberType = MethodInfo.ReturnType;
202 m.XmlAttributes = new XmlAttributes (MethodInfo.ReturnTypeCustomAttributeProvider);
203 m.SoapAttributes = new SoapAttributes (MethodInfo.ReturnTypeCustomAttributeProvider);
205 if (optional_ns != null)
206 m.XmlAttributes.XmlElements.Add (optional_ns);
211 for (int i = 0; i < output.Length; i++)
\r
213 m = new XmlReflectionMember ();
214 m.IsReturnValue = false;
215 m.MemberName = output [i].Name;
216 m.MemberType = output [i].ParameterType;
217 m.XmlAttributes = new XmlAttributes (output[i]);
218 m.SoapAttributes = new SoapAttributes (output[i]);
220 if (m.MemberType.IsByRef)
221 m.MemberType = m.MemberType.GetElementType ();
222 if (optional_ns != null)
223 m.XmlAttributes.XmlElements.Add (optional_ns);
224 out_members [i + idx] = m;
229 static void e (object o, XmlNodeEventArgs a)
231 Console.WriteLine ("Unexpected Node: {5}:{6} {0}/{1}/{2}/{3}/{4}",
232 a.LocalName, a.Name, a.NamespaceURI, a.NodeType, a.Text,
233 a.LineNumber, a.LinePosition);
234 // throw new Exception ();
239 // Holds the metadata loaded from the type stub, as well as
240 // the metadata for all the methods in the type
242 internal class TypeStubInfo {
243 Hashtable name_to_method = new Hashtable ();
246 internal SoapParameterStyle ParameterStyle;
247 internal SoapServiceRoutingStyle RoutingStyle;
248 internal SoapBindingUse Use;
249 internal string WebServiceName;
250 internal string WebServiceNamespace;
251 internal string BindingLocation;
252 internal string BindingName;
253 internal string BindingNamespace;
255 void GetTypeAttributes (Type t)
259 o = t.GetCustomAttributes (typeof (WebServiceBindingAttribute), false);
261 throw new Exception ("Expected WebServiceBindingAttribute on "+ t.Name);
262 WebServiceBindingAttribute b = (WebServiceBindingAttribute) o [0];
263 BindingLocation = b.Location;
264 BindingName = b.Name;
265 BindingNamespace = b.Namespace;
267 o = t.GetCustomAttributes (typeof (WebService), false);
269 WebServiceAttribute a = (WebServiceAttribute) o [0];
271 WebServiceName = a.Name;
272 WebServiceNamespace = a.Namespace;
274 WebServiceName = t.Name;
275 WebServiceNamespace = WebServiceAttribute.DefaultNamespace;
278 o = t.GetCustomAttributes (typeof (SoapDocumentServiceAttribute), false);
280 SoapDocumentServiceAttribute a = (SoapDocumentServiceAttribute) o [0];
282 ParameterStyle = a.ParameterStyle;
283 RoutingStyle = a.RoutingStyle;
286 o = t.GetCustomAttributes (typeof (SoapRpcServiceAttribute), false);
288 SoapRpcServiceAttribute srs = (SoapRpcServiceAttribute) o [0];
290 ParameterStyle = SoapParameterStyle.Wrapped;
291 RoutingStyle = srs.RoutingStyle;
292 Use = SoapBindingUse.Literal;
294 ParameterStyle = SoapParameterStyle.Wrapped;
295 RoutingStyle = SoapServiceRoutingStyle.SoapAction;
296 Use = SoapBindingUse.Literal;
302 // Extract all method information
304 void GetTypeMethods (Type t, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter)
306 MethodInfo [] type_methods = t.GetMethods (BindingFlags.Instance | BindingFlags.Public);
307 LogicalMethodInfo [] methods = LogicalMethodInfo.Create (type_methods, LogicalMethodTypes.Sync);
309 foreach (LogicalMethodInfo mi in methods){
310 MethodStubInfo msi = MethodStubInfo.Create (this, mi, xmlImporter, soapImporter);
315 name_to_method [msi.Name] = msi;
319 internal TypeStubInfo (Type t)
321 GetTypeAttributes (t);
323 XmlReflectionImporter xmlImporter = new XmlReflectionImporter ();
324 SoapReflectionImporter soapImporter = new SoapReflectionImporter ();
325 GetTypeMethods (t, xmlImporter, soapImporter);
328 internal MethodStubInfo GetMethod (string name)
330 return (MethodStubInfo) name_to_method [name];
337 internal class TypeStubManager {
338 static Hashtable type_to_manager;
340 static TypeStubManager ()
342 type_to_manager = new Hashtable ();
346 // This needs to be thread safe
348 static internal TypeStubInfo GetTypeStub (Type t)
350 TypeStubInfo tm = (TypeStubInfo) type_to_manager [t];
355 lock (typeof (TypeStubInfo)){
356 tm = (TypeStubInfo) type_to_manager [t];
361 tm = new TypeStubInfo (t);
362 type_to_manager [t] = tm;