2 // System.Runtime.Remoting.SoapServices.cs
4 // Author: Jaime Anguiano Olarra (jaime@gnome.org)
5 // Lluis Sanchez Gual (lluis@ximian.com)
7 // (c) 2002, Jaime Anguiano Olarra
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System.Collections;
36 using System.Runtime.Remoting;
37 using System.Runtime.Remoting.Metadata;
38 using System.Reflection;
39 using System.Runtime.InteropServices;
41 namespace System.Runtime.Remoting {
44 [System.Runtime.InteropServices.ComVisible (true)]
46 public class SoapServices
48 static Hashtable _xmlTypes = new Hashtable ();
49 static Hashtable _xmlElements = new Hashtable ();
50 static Hashtable _soapActions = new Hashtable ();
51 static Hashtable _soapActionsMethods = new Hashtable ();
52 static Hashtable _typeInfos = new Hashtable ();
56 public Hashtable Attributes;
57 public Hashtable Elements;
60 // Private constructor: nobody instantiates this class
61 private SoapServices () {}
65 public static string XmlNsForClrType
67 get { return "http://schemas.microsoft.com/clr/"; }
70 public static string XmlNsForClrTypeWithAssembly
72 get { return "http://schemas.microsoft.com/clr/assem/"; }
75 public static string XmlNsForClrTypeWithNs
77 get { return "http://schemas.microsoft.com/clr/ns/"; }
80 public static string XmlNsForClrTypeWithNsAndAssembly
82 get { return "http://schemas.microsoft.com/clr/nsassem/"; }
88 public static string CodeXmlNamespaceForClrTypeNamespace (string typeNamespace,
91 // If assemblyName is empty, then use the corlib namespace
93 if (assemblyName == string.Empty)
94 return XmlNsForClrTypeWithNs + typeNamespace;
95 else if (typeNamespace == string.Empty)
96 return EncodeNs (XmlNsForClrTypeWithAssembly + assemblyName);
98 return EncodeNs (XmlNsForClrTypeWithNsAndAssembly + typeNamespace + "/" + assemblyName);
101 public static bool DecodeXmlNamespaceForClrTypeNamespace (string inNamespace,
102 out string typeNamespace,
103 out string assemblyName) {
105 if (inNamespace == null) throw new ArgumentNullException ("inNamespace");
107 inNamespace = DecodeNs (inNamespace);
108 typeNamespace = null;
111 if (inNamespace.StartsWith(XmlNsForClrTypeWithNsAndAssembly))
113 int typePos = XmlNsForClrTypeWithNsAndAssembly.Length;
114 if (typePos >= inNamespace.Length) return false;
115 int assemPos = inNamespace.IndexOf ('/', typePos+1);
116 if (assemPos == -1) return false;
117 typeNamespace = inNamespace.Substring (typePos, assemPos - typePos);
118 assemblyName = inNamespace.Substring (assemPos+1);
121 else if (inNamespace.StartsWith(XmlNsForClrTypeWithNs))
123 int typePos = XmlNsForClrTypeWithNs.Length;
124 typeNamespace = inNamespace.Substring (typePos);
127 else if (inNamespace.StartsWith(XmlNsForClrTypeWithAssembly))
129 int typePos = XmlNsForClrTypeWithAssembly.Length;
130 assemblyName = inNamespace.Substring (typePos);
137 public static void GetInteropFieldTypeAndNameFromXmlAttribute (Type containingType,
138 string xmlAttribute, string xmlNamespace,
139 out Type type, out string name)
141 TypeInfo tf = (TypeInfo) _typeInfos [containingType];
142 Hashtable ht = tf != null ? tf.Attributes : null;
143 GetInteropFieldInfo (ht, xmlAttribute, xmlNamespace, out type, out name);
146 public static void GetInteropFieldTypeAndNameFromXmlElement (Type containingType,
147 string xmlElement, string xmlNamespace,
148 out Type type, out string name)
150 TypeInfo tf = (TypeInfo) _typeInfos [containingType];
151 Hashtable ht = tf != null ? tf.Elements : null;
152 GetInteropFieldInfo (ht, xmlElement, xmlNamespace, out type, out name);
155 static void GetInteropFieldInfo (Hashtable fields,
156 string xmlName, string xmlNamespace,
157 out Type type, out string name)
161 FieldInfo field = (FieldInfo) fields [GetNameKey (xmlName, xmlNamespace)];
164 type = field.FieldType;
173 static string GetNameKey (string name, string namspace)
175 if (namspace == null) return name;
176 else return name + " " + namspace;
179 public static Type GetInteropTypeFromXmlElement (string xmlElement, string xmlNamespace)
181 lock (_xmlElements.SyncRoot)
183 return (Type) _xmlElements [xmlElement + " " + xmlNamespace];
187 public static Type GetInteropTypeFromXmlType (string xmlType, string xmlTypeNamespace)
189 lock (_xmlTypes.SyncRoot)
191 return (Type) _xmlTypes [xmlType + " " + xmlTypeNamespace];
195 private static string GetAssemblyName(MethodBase mb)
197 if (mb.DeclaringType.Assembly == typeof (object).Assembly)
200 return mb.DeclaringType.Assembly.GetName().Name;
203 public static string GetSoapActionFromMethodBase (MethodBase mb)
205 return InternalGetSoapAction (mb);
208 public static bool GetTypeAndMethodNameFromSoapAction (string soapAction,
210 out string methodName)
212 lock (_soapActions.SyncRoot)
214 MethodBase mb = (MethodBase) _soapActionsMethods [soapAction];
217 typeName = mb.DeclaringType.AssemblyQualifiedName;
218 methodName = mb.Name;
229 int i = soapAction.LastIndexOf ('#');
230 if (i == -1) return false;
232 methodName = soapAction.Substring (i+1);
234 if (!DecodeXmlNamespaceForClrTypeNamespace (soapAction.Substring (0,i), out type, out assembly) )
237 if (assembly == null)
238 typeName = type + ", " + typeof (object).Assembly.GetName().Name;
240 typeName = type + ", " + assembly;
245 public static bool GetXmlElementForInteropType (Type type, out string xmlElement, out string xmlNamespace)
247 SoapTypeAttribute att = (SoapTypeAttribute) InternalRemotingServices.GetCachedSoapAttribute (type);
248 if (!att.IsInteropXmlElement)
255 xmlElement = att.XmlElementName;
256 xmlNamespace = att.XmlNamespace;
260 public static string GetXmlNamespaceForMethodCall (MethodBase mb)
262 return CodeXmlNamespaceForClrTypeNamespace (mb.DeclaringType.FullName, GetAssemblyName(mb));
265 public static string GetXmlNamespaceForMethodResponse (MethodBase mb)
267 return CodeXmlNamespaceForClrTypeNamespace (mb.DeclaringType.FullName, GetAssemblyName(mb));
270 public static bool GetXmlTypeForInteropType (Type type, out string xmlType, out string xmlTypeNamespace)
272 SoapTypeAttribute att = (SoapTypeAttribute) InternalRemotingServices.GetCachedSoapAttribute (type);
274 if (!att.IsInteropXmlType)
277 xmlTypeNamespace = null;
281 xmlType = att.XmlTypeName;
282 xmlTypeNamespace = att.XmlTypeNamespace;
286 public static bool IsClrTypeNamespace (string namespaceString)
288 return namespaceString.StartsWith (XmlNsForClrType);
291 public static bool IsSoapActionValidForMethodBase (string soapAction, MethodBase mb)
295 GetTypeAndMethodNameFromSoapAction (soapAction, out typeName, out methodName);
297 if (methodName != mb.Name) return false;
299 string methodClassType = mb.DeclaringType.AssemblyQualifiedName;
300 return typeName == methodClassType;
303 public static void PreLoad (Assembly assembly)
305 foreach (Type t in assembly.GetTypes ())
309 public static void PreLoad (Type type)
311 string name, namspace;
312 TypeInfo tf = _typeInfos [type] as TypeInfo;
313 if (tf != null) return;
315 if (GetXmlTypeForInteropType (type, out name, out namspace))
316 RegisterInteropXmlType (name, namspace, type);
318 if (GetXmlElementForInteropType (type, out name, out namspace))
319 RegisterInteropXmlElement (name, namspace, type);
321 lock (_typeInfos.SyncRoot)
323 tf = new TypeInfo ();
324 FieldInfo[] fields = type.GetFields (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
326 foreach (FieldInfo field in fields)
328 SoapFieldAttribute att = (SoapFieldAttribute) InternalRemotingServices.GetCachedSoapAttribute (field);
329 if (!att.IsInteropXmlElement ()) continue;
331 string key = GetNameKey (att.XmlElementName, att.XmlNamespace);
332 if (att.UseAttribute)
334 if (tf.Attributes == null) tf.Attributes = new Hashtable ();
335 tf.Attributes [key] = field;
339 if (tf.Elements == null) tf.Elements = new Hashtable ();
340 tf.Elements [key] = field;
343 _typeInfos [type] = tf;
347 public static void RegisterInteropXmlElement (string xmlElement, string xmlNamespace, Type type)
349 lock (_xmlElements.SyncRoot)
351 _xmlElements [xmlElement + " " + xmlNamespace] = type;
355 public static void RegisterInteropXmlType (string xmlType, string xmlTypeNamespace, Type type)
357 lock (_xmlTypes.SyncRoot)
359 _xmlTypes [xmlType + " " + xmlTypeNamespace] = type;
363 public static void RegisterSoapActionForMethodBase (MethodBase mb)
365 InternalGetSoapAction (mb);
368 static string InternalGetSoapAction (MethodBase mb)
370 lock (_soapActions.SyncRoot)
372 string action = (string) _soapActions [mb];
375 SoapMethodAttribute att = (SoapMethodAttribute) InternalRemotingServices.GetCachedSoapAttribute (mb);
376 action = att.SoapAction;
377 _soapActions [mb] = action;
378 _soapActionsMethods [action] = mb;
384 public static void RegisterSoapActionForMethodBase (MethodBase mb, string soapAction)
386 lock (_soapActions.SyncRoot)
388 _soapActions [mb] = soapAction;
389 _soapActionsMethods [soapAction] = mb;
393 static string EncodeNs (string ns)
395 // Simple url encoding for namespaces
397 ns = ns.Replace (",","%2C");
398 ns = ns.Replace (" ","%20");
399 return ns.Replace ("=","%3D");
402 static string DecodeNs (string ns)
404 ns = ns.Replace ("%2C",",");
405 ns = ns.Replace ("%20"," ");
406 return ns.Replace ("%3D","=");