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 WebClientProtocol derivative stub class
24 internal class MethodStubInfo
26 internal LogicalMethodInfo MethodInfo;
27 internal TypeStubInfo TypeStub;
29 // The name used by the stub class to reference this method.
31 internal WebMethodAttribute MethodAttribute;
33 internal string OperationName
35 get { return MethodInfo.Name; }
41 public MethodStubInfo (TypeStubInfo parent, LogicalMethodInfo source)
46 object [] o = source.GetCustomAttributes (typeof (WebMethodAttribute));
49 MethodAttribute = (WebMethodAttribute) o [0];
50 Name = MethodAttribute.MessageName;
51 if (Name == "") Name = source.Name;
59 // Holds the metadata loaded from the type stub, as well as
60 // the metadata for all the methods in the type
62 internal class TypeStubInfo
64 Hashtable name_to_method = new Hashtable ();
65 MethodStubInfo[] methods;
66 ArrayList bindings = new ArrayList ();
67 LogicalTypeInfo logicalType;
68 string defaultBinding;
70 XmlSerializer[] serializers;
72 public TypeStubInfo (LogicalTypeInfo logicalTypeInfo)
74 this.logicalType = logicalTypeInfo;
76 defaultBinding = logicalType.WebServiceName + ProtocolName;
77 BindingInfo binfo = new BindingInfo (defaultBinding, logicalType.WebServiceNamespace);
81 public LogicalTypeInfo LogicalType
83 get { return logicalType; }
88 get { return logicalType.Type; }
91 public string DefaultBinding
93 get { return defaultBinding; }
96 public virtual XmlReflectionImporter XmlImporter
101 public virtual SoapReflectionImporter SoapImporter
106 public virtual string ProtocolName
111 public XmlSerializer GetSerializer (int n)
113 return serializers [n];
116 public int RegisterSerializer (XmlMapping map)
118 if (mappings == null) mappings = new ArrayList ();
119 return mappings.Add (map);
122 public void Initialize ()
126 if (mappings != null)
128 // Build all the serializers at once
129 XmlMapping[] maps = (XmlMapping[]) mappings.ToArray(typeof(XmlMapping));
130 serializers = XmlSerializer.FromMappings (maps);
135 // Extract all method information
137 protected virtual void BuildTypeMethods ()
139 bool isClientProxy = typeof(WebClientProtocol).IsAssignableFrom (Type);
141 ArrayList metStubs = new ArrayList ();
142 foreach (LogicalMethodInfo mi in logicalType.LogicalMethods)
144 if (!isClientProxy && mi.CustomAttributeProvider.GetCustomAttributes (typeof(WebMethodAttribute), true).Length == 0)
147 MethodStubInfo msi = CreateMethodStubInfo (this, mi, isClientProxy);
152 if (name_to_method.ContainsKey (msi.Name)) {
153 string msg = "Both " + msi.MethodInfo.ToString () + " and " + GetMethod (msi.Name).MethodInfo + " use the message name '" + msi.Name + "'. ";
154 msg += "Use the MessageName property of WebMethod custom attribute to specify unique message names for the methods";
155 throw new InvalidOperationException (msg);
158 name_to_method [msi.Name] = msi;
161 methods = (MethodStubInfo[]) metStubs.ToArray (typeof (MethodStubInfo));
164 protected virtual MethodStubInfo CreateMethodStubInfo (TypeStubInfo typeInfo, LogicalMethodInfo methodInfo, bool isClientProxy)
166 return new MethodStubInfo (typeInfo, methodInfo);
169 public MethodStubInfo GetMethod (string name)
171 return (MethodStubInfo) name_to_method [name];
174 public MethodStubInfo[] Methods
176 get { return methods; }
179 internal ArrayList Bindings
181 get { return bindings; }
184 internal BindingInfo GetBinding (string name)
186 for (int n=0; n<bindings.Count; n++)
187 if (((BindingInfo)bindings[n]).Name == name) return (BindingInfo)bindings[n];
192 internal class BindingInfo
194 public BindingInfo (WebServiceBindingAttribute at, string ns)
197 Namespace = at.Namespace;
198 if (Namespace == "") Namespace = ns;
199 Location = at.Location;
202 public BindingInfo (string name, string ns)
209 public string Namespace;
210 public string Location;
215 // This class has information abou a web service. Through providess
216 // access to the TypeStubInfo instances for each protocol.
218 internal class LogicalTypeInfo
220 LogicalMethodInfo[] logicalMethods;
222 internal string WebServiceName;
223 internal string WebServiceNamespace;
224 internal string WebServiceLiteralNamespace;
225 internal string WebServiceEncodedNamespace;
226 internal string WebServiceAbstractNamespace;
227 internal string Description;
230 TypeStubInfo soapProtocol;
231 TypeStubInfo httpGetProtocol;
232 TypeStubInfo httpPostProtocol;
234 public LogicalTypeInfo (Type t)
238 object [] o = Type.GetCustomAttributes (typeof (WebServiceAttribute), false);
240 WebServiceAttribute a = (WebServiceAttribute) o [0];
241 WebServiceName = (a.Name != string.Empty) ? a.Name : Type.Name;
242 WebServiceNamespace = (a.Namespace != string.Empty) ? a.Namespace : WebServiceAttribute.DefaultNamespace;
243 Description = a.Description;
245 WebServiceName = Type.Name;
246 WebServiceNamespace = WebServiceAttribute.DefaultNamespace;
249 // Determine the namespaces for literal and encoded schema types
251 bool encoded = false;
253 o = t.GetCustomAttributes (typeof(SoapDocumentServiceAttribute), true);
255 SoapDocumentServiceAttribute at = (SoapDocumentServiceAttribute) o[0];
256 encoded = (at.Use == SoapBindingUse.Encoded);
258 else if (t.GetCustomAttributes (typeof(SoapRpcServiceAttribute), true).Length > 0)
261 string sep = WebServiceNamespace.EndsWith ("/") ? "" : "/";
264 WebServiceEncodedNamespace = WebServiceNamespace;
265 WebServiceLiteralNamespace = WebServiceNamespace + sep + "literalTypes";
268 WebServiceEncodedNamespace = WebServiceNamespace + sep + "encodedTypes";
269 WebServiceLiteralNamespace = WebServiceNamespace;
272 WebServiceAbstractNamespace = WebServiceNamespace + sep + "AbstractTypes";
274 MethodInfo [] type_methods = Type.GetMethods (BindingFlags.Instance | BindingFlags.Public);
275 logicalMethods = LogicalMethodInfo.Create (type_methods, LogicalMethodTypes.Sync);
278 public LogicalMethodInfo[] LogicalMethods
280 get { return logicalMethods; }
283 public TypeStubInfo GetTypeStub (string protocolName)
287 switch (protocolName)
290 if (soapProtocol == null) soapProtocol = CreateTypeStubInfo (typeof(SoapTypeStubInfo));
293 if (httpGetProtocol == null) httpGetProtocol = CreateTypeStubInfo (typeof(HttpGetTypeStubInfo));
294 return httpGetProtocol;
296 if (httpPostProtocol == null) httpPostProtocol = CreateTypeStubInfo (typeof(HttpPostTypeStubInfo));
297 return httpPostProtocol;
300 throw new InvalidOperationException ("Protocol " + protocolName + " not supported");
303 TypeStubInfo CreateTypeStubInfo (Type type)
305 TypeStubInfo tsi = (TypeStubInfo) Activator.CreateInstance (type, new object[] {this});
310 public string GetWebServiceNamespace (SoapBindingUse use)
312 if (use == SoapBindingUse.Literal) return WebServiceLiteralNamespace;
313 else return WebServiceEncodedNamespace;
319 // Manages type stubs
321 internal class TypeStubManager
323 static Hashtable type_to_manager;
325 static TypeStubManager ()
327 type_to_manager = new Hashtable ();
330 static internal TypeStubInfo GetTypeStub (Type t, string protocolName)
332 LogicalTypeInfo tm = GetLogicalTypeInfo (t);
333 return tm.GetTypeStub (protocolName);
337 // This needs to be thread safe
339 static internal LogicalTypeInfo GetLogicalTypeInfo (Type t)
341 LogicalTypeInfo tm = (LogicalTypeInfo) type_to_manager [t];
346 lock (typeof (LogicalTypeInfo))
348 tm = (LogicalTypeInfo) type_to_manager [t];
353 tm = new LogicalTypeInfo (t);
354 type_to_manager [t] = tm;