2 // Methods.cs: Information about a method and its mapping to a SOAP web service.
6 // Lluis Sanchez Gual (lluis@ximian.com)
8 // (C) 2003 Ximian, Inc.
11 using System.Reflection;
12 using System.Collections;
14 using System.Xml.Serialization;
15 using System.Web.Services;
16 using System.Web.Services.Description;
18 namespace System.Web.Services.Protocols {
21 // This class represents all the information we extract from a MethodInfo
22 // in the SoapHttpClientProtocol derivative stub class
24 internal class SoapMethodStubInfo : MethodStubInfo
26 internal string Action;
27 internal string Binding;
29 // The name/namespace of the request
30 internal string RequestName;
31 internal string RequestNamespace;
33 // The name/namespace of the response.
34 internal string ResponseName;
35 internal string ResponseNamespace;
38 internal SoapParameterStyle ParameterStyle;
39 internal SoapBindingStyle SoapBindingStyle;
40 internal SoapBindingUse Use;
42 internal HeaderInfo[] Headers;
43 internal SoapExtensionRuntimeConfig[] SoapExtensions;
45 internal XmlMembersMapping InputMembersMapping;
46 internal XmlMembersMapping OutputMembersMapping;
48 private int requestSerializerId;
49 private int responseSerializerId;
51 internal XmlSerializer RequestSerializer
53 get { return TypeStub.GetSerializer (requestSerializerId); }
56 internal XmlSerializer ResponseSerializer
58 get { return TypeStub.GetSerializer (responseSerializerId); }
64 public SoapMethodStubInfo (TypeStubInfo typeStub, LogicalMethodInfo source, object kind, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter)
65 : base (typeStub, source)
67 SoapTypeStubInfo parent = (SoapTypeStubInfo) typeStub;
68 XmlElementAttribute optional_ns = null;
73 RequestNamespace = "";
75 ResponseNamespace = "";
76 ParameterStyle = parent.ParameterStyle;
77 SoapBindingStyle = parent.SoapBindingStyle;
80 else if (kind is SoapDocumentMethodAttribute){
81 SoapDocumentMethodAttribute dma = (SoapDocumentMethodAttribute) kind;
84 if (Use == SoapBindingUse.Default) {
85 if (parent.SoapBindingStyle == SoapBindingStyle.Document)
88 Use = SoapBindingUse.Literal;
92 Binding = dma.Binding;
93 RequestName = dma.RequestElementName;
94 RequestNamespace = dma.RequestNamespace;
95 ResponseName = dma.ResponseElementName;
96 ResponseNamespace = dma.ResponseNamespace;
97 ParameterStyle = dma.ParameterStyle;
98 if (ParameterStyle == SoapParameterStyle.Default)
99 ParameterStyle = parent.ParameterStyle;
101 SoapBindingStyle = SoapBindingStyle.Document;
103 SoapRpcMethodAttribute rma = (SoapRpcMethodAttribute) kind;
104 Use = SoapBindingUse.Encoded; // RPC always use encoded
107 Binding = rma.Binding;
108 RequestName = rma.RequestElementName;
109 RequestNamespace = rma.RequestNamespace;
110 ResponseNamespace = rma.ResponseNamespace;
111 ResponseName = rma.ResponseElementName;
112 ParameterStyle = SoapParameterStyle.Wrapped;
114 SoapBindingStyle = SoapBindingStyle.Rpc;
116 // For RPC calls, make all arguments be part of the empty namespace
117 optional_ns = new XmlElementAttribute ();
118 optional_ns.Namespace = "";
122 if (source.ReturnType != typeof (void))
123 throw new Exception ("OneWay methods should not have a return value");
124 if (source.OutParameters.Length != 0)
125 throw new Exception ("OneWay methods should not have out/ref parameters");
128 if (RequestNamespace == "") RequestNamespace = parent.LogicalType.GetWebServiceNamespace (Use);
129 if (ResponseNamespace == "") ResponseNamespace = parent.LogicalType.GetWebServiceNamespace (Use);
130 if (RequestName == "") RequestName = Name;
131 if (ResponseName == "") ResponseName = Name + "Response";
132 if (Binding == null || Binding == "") Binding = parent.DefaultBinding;
133 else if (parent.GetBinding (Binding) == null) throw new InvalidOperationException ("Type '" + parent.Type + "' is missing WebServiceBinding attribute that defines a binding named '" + Binding + "'");
135 if (Action == null || Action == "")
136 Action = RequestNamespace.EndsWith("/") ? (RequestNamespace + Name) : (RequestNamespace + "/" + Name);
138 bool hasWrappingElem = (ParameterStyle == SoapParameterStyle.Wrapped);
139 bool writeAccessors = (SoapBindingStyle == SoapBindingStyle.Rpc);
141 XmlReflectionMember [] in_members = BuildRequestReflectionMembers (optional_ns);
142 XmlReflectionMember [] out_members = BuildResponseReflectionMembers (optional_ns);
144 if (Use == SoapBindingUse.Literal) {
145 InputMembersMapping = xmlImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, hasWrappingElem);
146 OutputMembersMapping = xmlImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, hasWrappingElem);
149 InputMembersMapping = soapImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, hasWrappingElem, writeAccessors);
150 OutputMembersMapping = soapImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, hasWrappingElem, writeAccessors);
153 requestSerializerId = parent.RegisterSerializer (InputMembersMapping);
154 responseSerializerId = parent.RegisterSerializer (OutputMembersMapping);
156 object[] o = source.GetCustomAttributes (typeof (SoapHeaderAttribute));
157 Headers = new HeaderInfo[o.Length];
158 for (int i = 0; i < o.Length; i++) {
159 SoapHeaderAttribute att = (SoapHeaderAttribute) o[i];
160 MemberInfo[] mems = source.DeclaringType.GetMember (att.MemberName);
161 if (mems.Length == 0) throw new InvalidOperationException ("Member " + att.MemberName + " not found in class " + source.DeclaringType.FullName);
163 Type headerType = (mems[0] is FieldInfo) ? ((FieldInfo)mems[0]).FieldType : ((PropertyInfo)mems[0]).PropertyType;
164 Headers [i] = new HeaderInfo (mems[0], att);
165 parent.RegisterHeaderType (headerType, Use);
168 SoapExtensions = SoapExtension.GetMethodExtensions (source);
171 XmlReflectionMember [] BuildRequestReflectionMembers (XmlElementAttribute optional_ns)
173 ParameterInfo [] input = MethodInfo.InParameters;
174 XmlReflectionMember [] in_members = new XmlReflectionMember [input.Length];
176 for (int i = 0; i < input.Length; i++)
178 XmlReflectionMember m = new XmlReflectionMember ();
179 m.IsReturnValue = false;
180 m.MemberName = input [i].Name;
181 m.MemberType = input [i].ParameterType;
183 m.XmlAttributes = new XmlAttributes (input[i]);
184 m.SoapAttributes = new SoapAttributes (input[i]);
186 if (m.MemberType.IsByRef)
187 m.MemberType = m.MemberType.GetElementType ();
188 if (optional_ns != null)
189 m.XmlAttributes.XmlElements.Add (optional_ns);
195 XmlReflectionMember [] BuildResponseReflectionMembers (XmlElementAttribute optional_ns)
197 ParameterInfo [] output = MethodInfo.OutParameters;
198 bool has_return_value = !(OneWay || MethodInfo.ReturnType == typeof (void));
199 XmlReflectionMember [] out_members = new XmlReflectionMember [(has_return_value ? 1 : 0) + output.Length];
200 XmlReflectionMember m;
203 if (has_return_value)
205 m = new XmlReflectionMember ();
206 m.IsReturnValue = true;
207 m.MemberName = RequestName + "Result";
208 m.MemberType = MethodInfo.ReturnType;
210 m.XmlAttributes = new XmlAttributes (MethodInfo.ReturnTypeCustomAttributeProvider);
211 m.SoapAttributes = new SoapAttributes (MethodInfo.ReturnTypeCustomAttributeProvider);
213 if (optional_ns != null)
214 m.XmlAttributes.XmlElements.Add (optional_ns);
219 for (int i = 0; i < output.Length; i++)
221 m = new XmlReflectionMember ();
222 m.IsReturnValue = false;
223 m.MemberName = output [i].Name;
224 m.MemberType = output [i].ParameterType;
225 m.XmlAttributes = new XmlAttributes (output[i]);
226 m.SoapAttributes = new SoapAttributes (output[i]);
228 if (m.MemberType.IsByRef)
229 m.MemberType = m.MemberType.GetElementType ();
230 if (optional_ns != null)
231 m.XmlAttributes.XmlElements.Add (optional_ns);
232 out_members [i + idx] = m;
237 public HeaderInfo GetHeaderInfo (Type headerType)
239 foreach (HeaderInfo headerInfo in Headers)
240 if (headerInfo.HeaderType == headerType) return headerInfo;
245 internal class HeaderInfo
247 internal MemberInfo Member;
248 internal SoapHeaderAttribute AttributeInfo;
249 internal Type HeaderType;
251 public HeaderInfo (MemberInfo member, SoapHeaderAttribute attributeInfo)
254 AttributeInfo = attributeInfo;
255 if (Member is PropertyInfo) HeaderType = ((PropertyInfo)Member).PropertyType;
256 else HeaderType = ((FieldInfo)Member).FieldType;
259 public object GetHeaderValue (object ob)
261 if (Member is PropertyInfo) return ((PropertyInfo)Member).GetValue (ob, null);
262 else return ((FieldInfo)Member).GetValue (ob);
265 public void SetHeaderValue (object ob, object value)
267 if (Member is PropertyInfo) ((PropertyInfo)Member).SetValue (ob, value, null);
268 else ((FieldInfo)Member).SetValue (ob, value);
271 public SoapHeaderDirection Direction
273 get { return AttributeInfo.Direction; }
277 // FIXME: this class should be internal, but it needs to be public in
278 // order to be serialized using XmlSerializer.
279 [SoapType (Namespace="http://schemas.xmlsoap.org/soap/envelope/")]
280 [XmlType (Namespace="http://schemas.xmlsoap.org/soap/envelope/")]
285 public Fault (SoapException ex)
288 faultstring = ex.Message;
289 faultactor = ex.Actor;
293 public XmlQualifiedName faultcode;
294 public string faultstring;
295 public string faultactor;
298 public XmlNode detail;
302 // Holds the metadata loaded from the type stub, as well as
303 // the metadata for all the methods in the type
305 internal class SoapTypeStubInfo : TypeStubInfo
307 Hashtable[] header_serializers = new Hashtable [3];
308 Hashtable[] header_serializers_byname = new Hashtable [3];
311 internal SoapParameterStyle ParameterStyle;
312 internal SoapServiceRoutingStyle RoutingStyle;
313 internal SoapBindingUse Use;
314 internal int faultSerializerLitId = -1;
315 internal int faultSerializerEncId = -1;
316 internal SoapExtensionRuntimeConfig[][] SoapExtensions;
317 internal SoapBindingStyle SoapBindingStyle;
318 internal XmlReflectionImporter xmlImporter;
319 internal SoapReflectionImporter soapImporter;
321 public SoapTypeStubInfo (LogicalTypeInfo logicalTypeInfo)
322 : base (logicalTypeInfo)
324 xmlImporter = new XmlReflectionImporter ();
325 soapImporter = new SoapReflectionImporter ();
329 o = Type.GetCustomAttributes (typeof (WebServiceBindingAttribute), false);
330 foreach (WebServiceBindingAttribute at in o)
331 Bindings.Add (new BindingInfo (at, LogicalType.WebServiceNamespace));
333 o = Type.GetCustomAttributes (typeof (SoapDocumentServiceAttribute), false);
335 SoapDocumentServiceAttribute a = (SoapDocumentServiceAttribute) o [0];
337 ParameterStyle = a.ParameterStyle;
338 RoutingStyle = a.RoutingStyle;
340 SoapBindingStyle = SoapBindingStyle.Document;
342 o = Type.GetCustomAttributes (typeof (SoapRpcServiceAttribute), false);
344 SoapRpcServiceAttribute srs = (SoapRpcServiceAttribute) o [0];
346 ParameterStyle = SoapParameterStyle.Wrapped;
347 RoutingStyle = srs.RoutingStyle;
348 Use = SoapBindingUse.Encoded;
349 SoapBindingStyle = SoapBindingStyle.Rpc;
351 ParameterStyle = SoapParameterStyle.Wrapped;
352 RoutingStyle = SoapServiceRoutingStyle.SoapAction;
353 Use = SoapBindingUse.Literal;
354 SoapBindingStyle = SoapBindingStyle.Document;
358 if (ParameterStyle == SoapParameterStyle.Default) ParameterStyle = SoapParameterStyle.Wrapped;
359 if (Use == SoapBindingUse.Default) Use = SoapBindingUse.Literal;
361 SoapExtensions = SoapExtension.GetTypeExtensions (Type);
364 public override XmlReflectionImporter XmlImporter
366 get { return xmlImporter; }
369 public override SoapReflectionImporter SoapImporter
371 get { return soapImporter; }
374 public override string ProtocolName
376 get { return "Soap"; }
379 protected override MethodStubInfo CreateMethodStubInfo (TypeStubInfo parent, LogicalMethodInfo lmi, bool isClientProxy)
381 SoapMethodStubInfo res = null;
382 object [] ats = lmi.GetCustomAttributes (typeof (SoapDocumentMethodAttribute));
383 if (ats.Length == 0) ats = lmi.GetCustomAttributes (typeof (SoapRpcMethodAttribute));
385 if (ats.Length == 0 && isClientProxy)
387 else if (ats.Length == 0)
388 res = new SoapMethodStubInfo (parent, lmi, null, xmlImporter, soapImporter);
390 res = new SoapMethodStubInfo (parent, lmi, ats[0], xmlImporter, soapImporter);
392 if (faultSerializerEncId == -1 && res.Use == SoapBindingUse.Encoded)
394 SoapReflectionImporter ri = new SoapReflectionImporter ();
395 XmlTypeMapping tm = ri.ImportTypeMapping (typeof(Fault));
396 faultSerializerEncId = RegisterSerializer (tm);
398 else if (faultSerializerLitId == -1 && res.Use == SoapBindingUse.Literal)
400 XmlReflectionImporter ri = new XmlReflectionImporter ();
401 XmlTypeMapping tm = ri.ImportTypeMapping (typeof(Fault));
402 faultSerializerLitId = RegisterSerializer (tm);
407 public XmlSerializer GetFaultSerializer (SoapBindingUse use)
409 if (use == SoapBindingUse.Literal)
410 return GetSerializer (faultSerializerLitId);
412 return GetSerializer (faultSerializerEncId);
415 internal void RegisterHeaderType (Type type, SoapBindingUse use)
417 Hashtable serializers = header_serializers [(int)use];
418 if (serializers == null) {
419 serializers = new Hashtable ();
420 header_serializers [(int)use] = serializers;
421 header_serializers_byname [(int)use] = new Hashtable ();
424 if (serializers.ContainsKey (type))
428 if (use == SoapBindingUse.Literal) {
429 XmlReflectionImporter ri = new XmlReflectionImporter ();
430 tm = ri.ImportTypeMapping (type, WebServiceAttribute.DefaultNamespace);
433 SoapReflectionImporter ri = new SoapReflectionImporter ();
434 tm = ri.ImportTypeMapping (type, WebServiceAttribute.DefaultNamespace);
437 int sid = RegisterSerializer (tm);
439 serializers [type] = sid;
440 header_serializers_byname [(int)use] [new XmlQualifiedName (tm.ElementName, tm.Namespace)] = sid;
443 internal XmlSerializer GetHeaderSerializer (Type type, SoapBindingUse use)
445 Hashtable table = header_serializers [(int)use];
446 if (table == null) return null;
448 return GetSerializer ((int) table [type]);
451 internal XmlSerializer GetHeaderSerializer (XmlQualifiedName qname, SoapBindingUse use)
453 Hashtable table = header_serializers_byname [(int)use];
454 if (table == null) return null;
456 return GetSerializer ((int) table [qname]);