LogicalMethodInfo.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. //
  2. // System.Web.Services.Protocols.LogicalMethodInfo.cs
  3. //
  4. // Authors:
  5. // Miguel de Icaza ([email protected])
  6. // Tim Coleman ([email protected])
  7. // Lluis Sanchez Gual ([email protected])
  8. //
  9. // Copyright (C) Tim Coleman, 2002
  10. // Copyright (C) Ximian, Inc, 2003
  11. //
  12. // TODO:
  13. // BeginInvoke, EndInvoke are missing.
  14. // AsyncResultParameter
  15. //
  16. // WILD GUESS:
  17. // The reason for this class is so that it can cluster method/begin/end methods
  18. // together, as the begin/end methods in generated files from WSDL does *NOT*
  19. // contain all the information required to make a request.
  20. //
  21. // Either that, or the Begin*/End* versions probe the attributes on the regular
  22. // method (which seems simpler).
  23. //
  24. //
  25. // Permission is hereby granted, free of charge, to any person obtaining
  26. // a copy of this software and associated documentation files (the
  27. // "Software"), to deal in the Software without restriction, including
  28. // without limitation the rights to use, copy, modify, merge, publish,
  29. // distribute, sublicense, and/or sell copies of the Software, and to
  30. // permit persons to whom the Software is furnished to do so, subject to
  31. // the following conditions:
  32. //
  33. // The above copyright notice and this permission notice shall be
  34. // included in all copies or substantial portions of the Software.
  35. //
  36. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  37. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  38. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  39. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  40. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  41. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  42. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  43. //
  44. using System.Reflection;
  45. using System.Collections;
  46. using System.Text;
  47. using System.Web.Services;
  48. namespace System.Web.Services.Protocols {
  49. public sealed class LogicalMethodInfo {
  50. #region Fields
  51. MethodInfo method_info, end_method_info;
  52. ParameterInfo [] parameters;
  53. ParameterInfo [] out_parameters;
  54. ParameterInfo [] in_parameters;
  55. WebMethodAttribute attribute;
  56. #endregion // Fields.
  57. #region Constructors
  58. public LogicalMethodInfo (MethodInfo method_info)
  59. {
  60. if (method_info == null)
  61. throw new ArgumentNullException ("method_info should be non-null");
  62. if (method_info.IsStatic)
  63. throw new InvalidOperationException ("method is static");
  64. this.method_info = method_info;
  65. }
  66. //
  67. // Only an internal contructor, called from "Create"
  68. //
  69. LogicalMethodInfo (MethodInfo method_info, MethodInfo end_method_info)
  70. {
  71. if (method_info == null)
  72. throw new ArgumentNullException ("method_info should be non-null");
  73. if (method_info.IsStatic)
  74. throw new InvalidOperationException ("method is static");
  75. this.end_method_info = end_method_info;
  76. }
  77. #endregion // Constructors
  78. #region Properties
  79. //
  80. // Signatures for Begin/End methods:
  81. //
  82. // public System.IAsyncResult BeginHelloWorld(ARG1, ARG2, System.AsyncCallback callback, object asyncState) {
  83. // public string EndHelloWorld(System.IAsyncResult asyncResult) {
  84. public ParameterInfo AsyncCallbackParameter {
  85. get {
  86. ParameterInfo [] pi = method_info.GetParameters ();
  87. return pi [pi.Length-2];
  88. }
  89. }
  90. public ParameterInfo AsyncResultParameter {
  91. get {
  92. ParameterInfo [] pi = end_method_info.GetParameters ();
  93. return pi [pi.Length-1];
  94. }
  95. }
  96. public ParameterInfo AsyncStateParameter {
  97. get {
  98. ParameterInfo [] pi = method_info.GetParameters ();
  99. return pi [pi.Length-1];
  100. }
  101. }
  102. public MethodInfo BeginMethodInfo {
  103. get {
  104. if (IsBeginMethod (method_info))
  105. return method_info;
  106. return null;
  107. }
  108. }
  109. public ICustomAttributeProvider CustomAttributeProvider {
  110. get {
  111. return method_info;
  112. }
  113. }
  114. public Type DeclaringType {
  115. get {
  116. return method_info.DeclaringType;
  117. }
  118. }
  119. public MethodInfo EndMethodInfo {
  120. get {
  121. return end_method_info;
  122. }
  123. }
  124. public ParameterInfo[] InParameters {
  125. get {
  126. if (parameters == null)
  127. ComputeParameters ();
  128. return in_parameters;
  129. }
  130. }
  131. public bool IsAsync {
  132. get {
  133. return end_method_info != null;
  134. }
  135. }
  136. public bool IsVoid {
  137. get {
  138. return ReturnType == typeof (void);
  139. }
  140. }
  141. public MethodInfo MethodInfo {
  142. get {
  143. return method_info;
  144. }
  145. }
  146. public string Name {
  147. get {
  148. return method_info.Name;
  149. }
  150. }
  151. void ComputeParameters ()
  152. {
  153. ParameterInfo[] pars = method_info.GetParameters ();
  154. if (IsAsync)
  155. {
  156. parameters = new ParameterInfo [pars.Length - 2];
  157. Array.Copy (pars, 0, parameters, 0, pars.Length - 2);
  158. in_parameters = new ParameterInfo [parameters.Length];
  159. parameters.CopyTo (in_parameters, 0);
  160. ParameterInfo[] outPars = end_method_info.GetParameters ();
  161. out_parameters = new ParameterInfo [outPars.Length - 1];
  162. Array.Copy (outPars, 0, out_parameters, 0, out_parameters.Length);
  163. }
  164. else
  165. {
  166. parameters = pars;
  167. int out_count = 0;
  168. int in_count = 0;
  169. foreach (ParameterInfo p in parameters){
  170. Type ptype = p.ParameterType;
  171. if (ptype.IsByRef){
  172. out_count++;
  173. if (!p.IsOut)
  174. in_count++;
  175. } else
  176. in_count++;
  177. }
  178. out_parameters = new ParameterInfo [out_count];
  179. int i = 0;
  180. for (int j = 0; j < parameters.Length; j++){
  181. if (parameters [j].ParameterType.IsByRef)
  182. out_parameters [i++] = parameters [j];
  183. }
  184. in_parameters = new ParameterInfo [in_count];
  185. i = 0;
  186. for (int j = 0; j < parameters.Length; j++){
  187. if (parameters [j].ParameterType.IsByRef){
  188. if (!parameters [j].IsOut)
  189. in_parameters [i++] = parameters [j];
  190. } else
  191. in_parameters [i++] = parameters [j];
  192. }
  193. }
  194. }
  195. public ParameterInfo[] OutParameters {
  196. get {
  197. if (parameters == null)
  198. ComputeParameters ();
  199. return out_parameters;
  200. }
  201. }
  202. public ParameterInfo[] Parameters {
  203. get {
  204. if (parameters == null)
  205. ComputeParameters ();
  206. return parameters;
  207. }
  208. }
  209. public Type ReturnType {
  210. get {
  211. if (IsAsync)
  212. return end_method_info.ReturnType;
  213. else
  214. return method_info.ReturnType;
  215. }
  216. }
  217. public ICustomAttributeProvider ReturnTypeCustomAttributeProvider {
  218. get {
  219. return method_info.ReturnTypeCustomAttributes;
  220. }
  221. }
  222. internal bool EnableSession {
  223. get {
  224. if (method_info == null)
  225. return false;
  226. if (attribute == null) {
  227. object [] o = method_info.GetCustomAttributes (false);
  228. foreach (Attribute att in o) {
  229. if (att is WebMethodAttribute) {
  230. attribute = (WebMethodAttribute) att;
  231. break;
  232. }
  233. }
  234. }
  235. return (attribute != null) ? attribute.EnableSession : false;
  236. }
  237. }
  238. #endregion // Properties
  239. #region Methods
  240. public IAsyncResult BeginInvoke (object target, object[] values, AsyncCallback callback, object asyncState)
  241. {
  242. int len = (values!=null) ? values.Length : 0;
  243. object[] pars = new object [len + 2];
  244. if (len > 0)
  245. values.CopyTo (pars, 0);
  246. pars [len] = callback;
  247. pars [len+1] = asyncState;
  248. return (IAsyncResult) method_info.Invoke (target, pars);
  249. }
  250. public static LogicalMethodInfo[] Create (MethodInfo[] method_infos)
  251. {
  252. return Create (method_infos, LogicalMethodTypes.Sync | LogicalMethodTypes.Async);
  253. }
  254. public static LogicalMethodInfo[] Create (MethodInfo[] method_infos, LogicalMethodTypes types)
  255. {
  256. ArrayList sync = ((types & LogicalMethodTypes.Sync) != 0) ? new ArrayList () : null;
  257. ArrayList begin, end;
  258. if ((types & LogicalMethodTypes.Async) != 0){
  259. begin = new ArrayList ();
  260. end = new ArrayList ();
  261. } else
  262. begin = end = null;
  263. foreach (MethodInfo mi in method_infos){
  264. if (IsBeginMethod (mi) && begin != null)
  265. begin.Add (mi);
  266. else if (IsEndMethod (mi) && end != null)
  267. end.Add (mi);
  268. else if (sync != null)
  269. sync.Add (mi);
  270. }
  271. int bcount = 0, count = 0;
  272. if (begin != null){
  273. bcount = count = begin.Count;
  274. if (count != end.Count)
  275. throw new InvalidOperationException ("Imbalance of begin/end methods");
  276. }
  277. if (sync != null)
  278. count += sync.Count;
  279. LogicalMethodInfo [] res = new LogicalMethodInfo [count];
  280. int dest = 0;
  281. if (begin != null){
  282. foreach (MethodInfo bm in begin){
  283. string end_name = "End" + bm.Name.Substring (5);
  284. for (int i = 0; i < bcount; i++){
  285. MethodInfo em = (MethodInfo) end [i];
  286. if (em.Name == end_name){
  287. res [dest++] = new LogicalMethodInfo (bm, em);
  288. break;
  289. }
  290. throw new InvalidOperationException ("Imbalance of begin/end methods");
  291. }
  292. }
  293. }
  294. if (sync != null)
  295. foreach (MethodInfo mi in sync){
  296. res [dest++] = new LogicalMethodInfo (mi);
  297. }
  298. return res;
  299. }
  300. public object[] EndInvoke (object target, IAsyncResult asyncResult)
  301. {
  302. if (parameters == null)
  303. ComputeParameters ();
  304. object[] values = new object [out_parameters.Length + 1];
  305. values [values.Length - 1] = asyncResult;
  306. object res = end_method_info.Invoke (target, values);
  307. int retc = IsVoid ? 0 : 1;
  308. object [] ret = new object [retc + out_parameters.Length];
  309. if (retc == 1) ret [0] = res;
  310. Array.Copy (values, 0, ret, retc, out_parameters.Length);
  311. return ret;
  312. }
  313. public object GetCustomAttribute (Type type)
  314. {
  315. return Attribute.GetCustomAttribute (method_info, type, true);
  316. }
  317. public object[] GetCustomAttributes (Type type)
  318. {
  319. return method_info.GetCustomAttributes (type, true);
  320. }
  321. public object[] Invoke (object target, object[] values)
  322. {
  323. if (parameters == null)
  324. ComputeParameters ();
  325. int retc = IsVoid ? 0 : 1;
  326. object [] ret = new object [retc + out_parameters.Length];
  327. object res = method_info.Invoke (target, values);
  328. if (retc == 1) ret [0] = res;
  329. int j = retc;
  330. for (int i = 0; i < parameters.Length; i++){
  331. if (parameters [i].ParameterType.IsByRef)
  332. ret [j++] = values [i];
  333. }
  334. return ret;
  335. }
  336. public static bool IsBeginMethod (MethodInfo method_info)
  337. {
  338. if (method_info == null)
  339. throw new ArgumentNullException ("method_info can not be null");
  340. if (method_info.ReturnType != typeof (IAsyncResult))
  341. return false;
  342. if (method_info.Name.StartsWith ("Begin"))
  343. return true;
  344. return false;
  345. }
  346. public static bool IsEndMethod (MethodInfo method_info)
  347. {
  348. if (method_info == null)
  349. throw new ArgumentNullException ("method_info can not be null");
  350. ParameterInfo [] parameter_info = method_info.GetParameters ();
  351. if (parameter_info.Length != 1)
  352. return false;
  353. if (parameter_info [0].ParameterType != typeof (IAsyncResult))
  354. return false;
  355. if (method_info.Name.StartsWith ("End"))
  356. return true;
  357. return false;
  358. }
  359. public override string ToString ()
  360. {
  361. StringBuilder sb = new StringBuilder ();
  362. if (parameters == null)
  363. ComputeParameters ();
  364. for (int i = 0; i < parameters.Length; i++){
  365. sb.Append (parameters [i].ParameterType);
  366. if (parameters [i].ParameterType.IsByRef)
  367. sb.Append (" ByRef");
  368. if (i+1 != parameters.Length)
  369. sb.Append (", ");
  370. }
  371. return String.Format (
  372. "{0} {1} ({2})",
  373. method_info.ReturnType, method_info.Name,
  374. sb.ToString ());
  375. }
  376. #endregion // Methods
  377. }
  378. }