PageRenderTime 164ms CodeModel.GetById 35ms RepoModel.GetById 1ms app.codeStats 1ms

/mcs/class/System.Web.Mvc/System.Web.Mvc/ReflectedActionDescriptor.cs

https://github.com/iainlane/mono
C# | 219 lines | 163 code | 36 blank | 20 comment | 29 complexity | 90d9721acabc0bdef95b51e7f2b4d0e0 MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation. All rights reserved.
  4. *
  5. * This software is subject to the Microsoft Public License (Ms-PL).
  6. * A copy of the license can be found in the license.htm file included
  7. * in this distribution.
  8. *
  9. * You must not remove this notice, or any other, from this software.
  10. *
  11. * ***************************************************************************/
  12. namespace System.Web.Mvc {
  13. using System;
  14. using System.Collections.Generic;
  15. using System.Globalization;
  16. using System.Linq;
  17. using System.Reflection;
  18. using System.Web.Mvc.Resources;
  19. public class ReflectedActionDescriptor : ActionDescriptor {
  20. private readonly static ActionMethodDispatcherCache _staticDispatcherCache = new ActionMethodDispatcherCache();
  21. private ActionMethodDispatcherCache _instanceDispatcherCache;
  22. private readonly string _actionName;
  23. private readonly ControllerDescriptor _controllerDescriptor;
  24. private ParameterDescriptor[] _parametersCache;
  25. public ReflectedActionDescriptor(MethodInfo methodInfo, string actionName, ControllerDescriptor controllerDescriptor)
  26. : this(methodInfo, actionName, controllerDescriptor, true /* validateMethod */) {
  27. }
  28. internal ReflectedActionDescriptor(MethodInfo methodInfo, string actionName, ControllerDescriptor controllerDescriptor, bool validateMethod) {
  29. if (methodInfo == null) {
  30. throw new ArgumentNullException("methodInfo");
  31. }
  32. if (String.IsNullOrEmpty(actionName)) {
  33. throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
  34. }
  35. if (controllerDescriptor == null) {
  36. throw new ArgumentNullException("controllerDescriptor");
  37. }
  38. if (validateMethod) {
  39. string failedMessage = VerifyActionMethodIsCallable(methodInfo);
  40. if (failedMessage != null) {
  41. throw new ArgumentException(failedMessage, "methodInfo");
  42. }
  43. }
  44. MethodInfo = methodInfo;
  45. _actionName = actionName;
  46. _controllerDescriptor = controllerDescriptor;
  47. }
  48. public override string ActionName {
  49. get {
  50. return _actionName;
  51. }
  52. }
  53. public override ControllerDescriptor ControllerDescriptor {
  54. get {
  55. return _controllerDescriptor;
  56. }
  57. }
  58. internal ActionMethodDispatcherCache DispatcherCache {
  59. get {
  60. if (_instanceDispatcherCache == null) {
  61. _instanceDispatcherCache = _staticDispatcherCache;
  62. }
  63. return _instanceDispatcherCache;
  64. }
  65. set {
  66. _instanceDispatcherCache = value;
  67. }
  68. }
  69. public MethodInfo MethodInfo {
  70. get;
  71. private set;
  72. }
  73. public override object Execute(ControllerContext controllerContext, IDictionary<string, object> parameters) {
  74. if (controllerContext == null) {
  75. throw new ArgumentNullException("controllerContext");
  76. }
  77. if (parameters == null) {
  78. throw new ArgumentNullException("parameters");
  79. }
  80. ParameterInfo[] parameterInfos = MethodInfo.GetParameters();
  81. var rawParameterValues = from parameterInfo in parameterInfos
  82. select ExtractParameterFromDictionary(parameterInfo, parameters, MethodInfo);
  83. object[] parametersArray = rawParameterValues.ToArray();
  84. ActionMethodDispatcher dispatcher = DispatcherCache.GetDispatcher(MethodInfo);
  85. object actionReturnValue = dispatcher.Execute(controllerContext.Controller, parametersArray);
  86. return actionReturnValue;
  87. }
  88. private static object ExtractParameterFromDictionary(ParameterInfo parameterInfo, IDictionary<string, object> parameters, MethodInfo methodInfo) {
  89. object value;
  90. if (!parameters.TryGetValue(parameterInfo.Name, out value)) {
  91. // the key should always be present, even if the parameter value is null
  92. string message = String.Format(CultureInfo.CurrentUICulture, MvcResources.ReflectedActionDescriptor_ParameterNotInDictionary,
  93. parameterInfo.Name, parameterInfo.ParameterType, methodInfo, methodInfo.DeclaringType);
  94. throw new ArgumentException(message, "parameters");
  95. }
  96. if (value == null && !TypeHelpers.TypeAllowsNullValue(parameterInfo.ParameterType)) {
  97. // tried to pass a null value for a non-nullable parameter type
  98. string message = String.Format(CultureInfo.CurrentUICulture, MvcResources.ReflectedActionDescriptor_ParameterCannotBeNull,
  99. parameterInfo.Name, parameterInfo.ParameterType, methodInfo, methodInfo.DeclaringType);
  100. throw new ArgumentException(message, "parameters");
  101. }
  102. if (value != null && !parameterInfo.ParameterType.IsInstanceOfType(value)) {
  103. // value was supplied but is not of the proper type
  104. string message = String.Format(CultureInfo.CurrentUICulture, MvcResources.ReflectedActionDescriptor_ParameterValueHasWrongType,
  105. parameterInfo.Name, methodInfo, methodInfo.DeclaringType, value.GetType(), parameterInfo.ParameterType);
  106. throw new ArgumentException(message, "parameters");
  107. }
  108. return value;
  109. }
  110. public override object[] GetCustomAttributes(bool inherit) {
  111. return MethodInfo.GetCustomAttributes(inherit);
  112. }
  113. public override object[] GetCustomAttributes(Type attributeType, bool inherit) {
  114. return MethodInfo.GetCustomAttributes(attributeType, inherit);
  115. }
  116. public override FilterInfo GetFilters() {
  117. // Enumerable.OrderBy() is a stable sort, so this method preserves scope ordering.
  118. FilterAttribute[] typeFilters = (FilterAttribute[])MethodInfo.ReflectedType.GetCustomAttributes(typeof(FilterAttribute), true /* inherit */);
  119. FilterAttribute[] methodFilters = (FilterAttribute[])MethodInfo.GetCustomAttributes(typeof(FilterAttribute), true /* inherit */);
  120. List<FilterAttribute> orderedFilters = typeFilters.Concat(methodFilters).OrderBy(attr => attr.Order).ToList();
  121. FilterInfo filterInfo = new FilterInfo();
  122. MergeFiltersIntoList(orderedFilters, filterInfo.ActionFilters);
  123. MergeFiltersIntoList(orderedFilters, filterInfo.AuthorizationFilters);
  124. MergeFiltersIntoList(orderedFilters, filterInfo.ExceptionFilters);
  125. MergeFiltersIntoList(orderedFilters, filterInfo.ResultFilters);
  126. return filterInfo;
  127. }
  128. public override ParameterDescriptor[] GetParameters() {
  129. ParameterDescriptor[] parameters = LazilyFetchParametersCollection();
  130. // need to clone array so that user modifications aren't accidentally stored
  131. return (ParameterDescriptor[])parameters.Clone();
  132. }
  133. public override ICollection<ActionSelector> GetSelectors() {
  134. ActionMethodSelectorAttribute[] attrs = (ActionMethodSelectorAttribute[])MethodInfo.GetCustomAttributes(typeof(ActionMethodSelectorAttribute), true /* inherit */);
  135. ActionSelector[] selectors = Array.ConvertAll(attrs, attr => (ActionSelector)(controllerContext => attr.IsValidForRequest(controllerContext, MethodInfo)));
  136. return selectors;
  137. }
  138. public override bool IsDefined(Type attributeType, bool inherit) {
  139. return MethodInfo.IsDefined(attributeType, inherit);
  140. }
  141. private ParameterDescriptor[] LazilyFetchParametersCollection() {
  142. return DescriptorUtil.LazilyFetchOrCreateDescriptors<ParameterInfo, ParameterDescriptor>(
  143. ref _parametersCache /* cacheLocation */,
  144. MethodInfo.GetParameters /* initializer */,
  145. parameterInfo => new ReflectedParameterDescriptor(parameterInfo, this) /* converter */);
  146. }
  147. private static void MergeFiltersIntoList<TFilter>(IList<FilterAttribute> allFilters, IList<TFilter> destFilters) where TFilter : class {
  148. foreach (FilterAttribute filter in allFilters) {
  149. TFilter castFilter = filter as TFilter;
  150. if (castFilter != null) {
  151. destFilters.Add(castFilter);
  152. }
  153. }
  154. }
  155. internal static ReflectedActionDescriptor TryCreateDescriptor(MethodInfo methodInfo, string name, ControllerDescriptor controllerDescriptor) {
  156. ReflectedActionDescriptor descriptor = new ReflectedActionDescriptor(methodInfo, name, controllerDescriptor, false /* validateMethod */);
  157. string failedMessage = VerifyActionMethodIsCallable(methodInfo);
  158. return (failedMessage == null) ? descriptor : null;
  159. }
  160. private static string VerifyActionMethodIsCallable(MethodInfo methodInfo) {
  161. // we can't call instance methods where the 'this' parameter is a type other than ControllerBase
  162. if (!methodInfo.IsStatic && !typeof(ControllerBase).IsAssignableFrom(methodInfo.ReflectedType)) {
  163. return String.Format(CultureInfo.CurrentUICulture, MvcResources.ReflectedActionDescriptor_CannotCallInstanceMethodOnNonControllerType,
  164. methodInfo, methodInfo.ReflectedType.FullName);
  165. }
  166. // we can't call methods with open generic type parameters
  167. if (methodInfo.ContainsGenericParameters) {
  168. return String.Format(CultureInfo.CurrentUICulture, MvcResources.ReflectedActionDescriptor_CannotCallOpenGenericMethods,
  169. methodInfo, methodInfo.ReflectedType.FullName);
  170. }
  171. // we can't call methods with ref/out parameters
  172. ParameterInfo[] parameterInfos = methodInfo.GetParameters();
  173. foreach (ParameterInfo parameterInfo in parameterInfos) {
  174. if (parameterInfo.IsOut || parameterInfo.ParameterType.IsByRef) {
  175. return String.Format(CultureInfo.CurrentUICulture, MvcResources.ReflectedActionDescriptor_CannotCallMethodsWithOutOrRefParameters,
  176. methodInfo, methodInfo.ReflectedType.FullName, parameterInfo);
  177. }
  178. }
  179. // we can call this method
  180. return null;
  181. }
  182. }
  183. }