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
= (LogicalTypeInfo
) type_to_manager
[t
];
402 tm
= new LogicalTypeInfo (t
);
403 type_to_manager
[t
] = tm
;