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.
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Reflection;
33 using System.Collections;
35 using System.Xml.Serialization;
36 using System.Web.Services;
37 using System.Web.Services.Description;
39 namespace System.Web.Services.Protocols {
42 // This class represents all the information we extract from a MethodInfo
43 // in the WebClientProtocol derivative stub class
45 internal class MethodStubInfo
47 internal LogicalMethodInfo MethodInfo;
48 internal TypeStubInfo TypeStub;
50 // The name used by the stub class to reference this method.
52 internal WebMethodAttribute MethodAttribute;
54 internal string OperationName
56 get { return MethodInfo.Name; }
62 public MethodStubInfo (TypeStubInfo parent, LogicalMethodInfo source)
67 object [] o = source.GetCustomAttributes (typeof (WebMethodAttribute));
70 MethodAttribute = (WebMethodAttribute) o [0];
71 Name = MethodAttribute.MessageName;
72 if (Name == "") Name = source.Name;
80 // Holds the metadata loaded from the type stub, as well as
81 // the metadata for all the methods in the type
83 internal class TypeStubInfo
85 Hashtable name_to_method = new Hashtable ();
86 MethodStubInfo[] methods;
87 ArrayList bindings = new ArrayList ();
88 LogicalTypeInfo logicalType;
89 string defaultBinding;
91 XmlSerializer[] serializers;
93 public TypeStubInfo (LogicalTypeInfo logicalTypeInfo)
95 this.logicalType = logicalTypeInfo;
97 defaultBinding = logicalType.WebServiceName + ProtocolName;
98 BindingInfo binfo = new BindingInfo (defaultBinding, logicalType.WebServiceNamespace);
102 public LogicalTypeInfo LogicalType
104 get { return logicalType; }
109 get { return logicalType.Type; }
112 public string DefaultBinding
114 get { return defaultBinding; }
117 public virtual XmlReflectionImporter XmlImporter
122 public virtual SoapReflectionImporter SoapImporter
127 public virtual string ProtocolName
132 public XmlSerializer GetSerializer (int n)
134 return serializers [n];
137 public int RegisterSerializer (XmlMapping map)
139 if (mappings == null) mappings = new ArrayList ();
140 return mappings.Add (map);
143 public void Initialize ()
147 if (mappings != null)
149 // Build all the serializers at once
150 XmlMapping[] maps = (XmlMapping[]) mappings.ToArray(typeof(XmlMapping));
151 serializers = XmlSerializer.FromMappings (maps);
156 // Extract all method information
158 protected virtual void BuildTypeMethods ()
160 bool isClientProxy = typeof(WebClientProtocol).IsAssignableFrom (Type);
162 ArrayList metStubs = new ArrayList ();
163 foreach (LogicalMethodInfo mi in logicalType.LogicalMethods)
165 if (!isClientProxy && mi.CustomAttributeProvider.GetCustomAttributes (typeof(WebMethodAttribute), true).Length == 0)
168 MethodStubInfo msi = CreateMethodStubInfo (this, mi, isClientProxy);
173 if (name_to_method.ContainsKey (msi.Name)) {
174 string msg = "Both " + msi.MethodInfo.ToString () + " and " + GetMethod (msi.Name).MethodInfo + " use the message name '" + msi.Name + "'. ";
175 msg += "Use the MessageName property of WebMethod custom attribute to specify unique message names for the methods";
176 throw new InvalidOperationException (msg);
179 name_to_method [msi.Name] = msi;
182 methods = (MethodStubInfo[]) metStubs.ToArray (typeof (MethodStubInfo));
185 protected virtual MethodStubInfo CreateMethodStubInfo (TypeStubInfo typeInfo, LogicalMethodInfo methodInfo, bool isClientProxy)
187 return new MethodStubInfo (typeInfo, methodInfo);
190 public MethodStubInfo GetMethod (string name)
192 return (MethodStubInfo) name_to_method [name];
195 public MethodStubInfo[] Methods
197 get { return methods; }
200 internal ArrayList Bindings
202 get { return bindings; }
205 internal void AddBinding (BindingInfo info)
210 internal BindingInfo GetBinding (string name)
212 if (name == null || name.Length == 0) return (BindingInfo) bindings[0];
214 for (int n=1; n<bindings.Count; n++)
215 if (((BindingInfo)bindings[n]).Name == name) return (BindingInfo)bindings[n];
220 internal class BindingInfo
222 public BindingInfo (WebServiceBindingAttribute at, string ns)
225 Namespace = at.Namespace;
226 if (Namespace == "") Namespace = ns;
227 Location = at.Location;
230 public BindingInfo (string name, string ns)
237 public string Namespace;
238 public string Location;
243 // This class has information abou a web service. Through providess
244 // access to the TypeStubInfo instances for each protocol.
246 internal class LogicalTypeInfo
248 LogicalMethodInfo[] logicalMethods;
250 internal string WebServiceName;
251 internal string WebServiceNamespace;
252 string WebServiceLiteralNamespace;
253 string WebServiceEncodedNamespace;
254 internal string WebServiceAbstractNamespace;
255 internal string Description;
259 TypeStubInfo soapProtocol;
260 TypeStubInfo httpGetProtocol;
261 TypeStubInfo httpPostProtocol;
263 public LogicalTypeInfo (Type t)
267 object [] o = Type.GetCustomAttributes (typeof (WebServiceAttribute), false);
269 WebServiceAttribute a = (WebServiceAttribute) o [0];
270 WebServiceName = (a.Name != string.Empty) ? a.Name : Type.Name;
271 WebServiceNamespace = (a.Namespace != string.Empty) ? a.Namespace : WebServiceAttribute.DefaultNamespace;
272 Description = a.Description;
274 WebServiceName = Type.Name;
275 WebServiceNamespace = WebServiceAttribute.DefaultNamespace;
278 // Determine the namespaces for literal and encoded schema types
282 o = t.GetCustomAttributes (typeof(SoapDocumentServiceAttribute), true);
284 SoapDocumentServiceAttribute at = (SoapDocumentServiceAttribute) o[0];
285 useEncoded = (at.Use == SoapBindingUse.Encoded);
287 else if (t.GetCustomAttributes (typeof(SoapRpcServiceAttribute), true).Length > 0)
290 string sep = WebServiceNamespace.EndsWith ("/") ? "" : "/";
293 WebServiceEncodedNamespace = WebServiceNamespace;
294 WebServiceLiteralNamespace = WebServiceNamespace + sep + "literalTypes";
297 WebServiceEncodedNamespace = WebServiceNamespace + sep + "encodedTypes";
298 WebServiceLiteralNamespace = WebServiceNamespace;
301 WebServiceAbstractNamespace = WebServiceNamespace + sep + "AbstractTypes";
303 MethodInfo [] type_methods = Type.GetMethods (BindingFlags.Instance | BindingFlags.Public);
304 logicalMethods = LogicalMethodInfo.Create (type_methods, LogicalMethodTypes.Sync);
307 public LogicalMethodInfo[] LogicalMethods
309 get { return logicalMethods; }
312 public TypeStubInfo GetTypeStub (string protocolName)
316 switch (protocolName)
319 if (soapProtocol == null) soapProtocol = CreateTypeStubInfo (typeof(SoapTypeStubInfo));
322 if (httpGetProtocol == null) httpGetProtocol = CreateTypeStubInfo (typeof(HttpGetTypeStubInfo));
323 return httpGetProtocol;
325 if (httpPostProtocol == null) httpPostProtocol = CreateTypeStubInfo (typeof(HttpPostTypeStubInfo));
326 return httpPostProtocol;
329 throw new InvalidOperationException ("Protocol " + protocolName + " not supported");
332 TypeStubInfo CreateTypeStubInfo (Type type)
334 TypeStubInfo tsi = (TypeStubInfo) Activator.CreateInstance (type, new object[] {this});
339 public string GetWebServiceLiteralNamespace (string baseNamespace)
342 string sep = baseNamespace.EndsWith ("/") ? "" : "/";
343 return baseNamespace + sep + "literalTypes";
346 return baseNamespace;
349 public string GetWebServiceEncodedNamespace (string baseNamespace)
352 return baseNamespace;
354 string sep = baseNamespace.EndsWith ("/") ? "" : "/";
355 return baseNamespace + sep + "encodedTypes";
359 public string GetWebServiceNamespace (string baseNamespace, SoapBindingUse use)
361 if (use == SoapBindingUse.Literal) return GetWebServiceLiteralNamespace (baseNamespace);
362 else return GetWebServiceEncodedNamespace (baseNamespace);
368 // Manages type stubs
370 internal class TypeStubManager
372 static Hashtable type_to_manager;
374 static TypeStubManager ()
376 type_to_manager = new Hashtable ();
379 static internal TypeStubInfo GetTypeStub (Type t, string protocolName)
381 LogicalTypeInfo tm = GetLogicalTypeInfo (t);
382 return tm.GetTypeStub (protocolName);
386 // This needs to be thread safe
388 static internal LogicalTypeInfo GetLogicalTypeInfo (Type t)
390 lock (type_to_manager)
392 LogicalTypeInfo tm = (LogicalTypeInfo) type_to_manager [t];
397 tm = new LogicalTypeInfo (t);
398 type_to_manager [t] = tm;