1 namespace System.Web.Mvc { 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Reflection; 6 using System.Web.Mvc.Resources; 7 8 public class ReflectedActionDescriptor : ActionDescriptor { 9 10 private readonly string _actionName; 11 private readonly ControllerDescriptor _controllerDescriptor; 12 private ParameterDescriptor[] _parametersCache; 13 private readonly Lazy<string> _uniqueId; 14 ReflectedActionDescriptor(MethodInfo methodInfo, string actionName, ControllerDescriptor controllerDescriptor)15 public ReflectedActionDescriptor(MethodInfo methodInfo, string actionName, ControllerDescriptor controllerDescriptor) 16 : this(methodInfo, actionName, controllerDescriptor, true /* validateMethod */) { 17 } 18 ReflectedActionDescriptor(MethodInfo methodInfo, string actionName, ControllerDescriptor controllerDescriptor, bool validateMethod)19 internal ReflectedActionDescriptor(MethodInfo methodInfo, string actionName, ControllerDescriptor controllerDescriptor, bool validateMethod) { 20 if (methodInfo == null) { 21 throw new ArgumentNullException("methodInfo"); 22 } 23 if (String.IsNullOrEmpty(actionName)) { 24 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName"); 25 } 26 if (controllerDescriptor == null) { 27 throw new ArgumentNullException("controllerDescriptor"); 28 } 29 30 if (validateMethod) { 31 string failedMessage = VerifyActionMethodIsCallable(methodInfo); 32 if (failedMessage != null) { 33 throw new ArgumentException(failedMessage, "methodInfo"); 34 } 35 } 36 37 MethodInfo = methodInfo; 38 _actionName = actionName; 39 _controllerDescriptor = controllerDescriptor; 40 _uniqueId = new Lazy<string>(CreateUniqueId); 41 } 42 43 public override string ActionName { 44 get { 45 return _actionName; 46 } 47 } 48 49 public override ControllerDescriptor ControllerDescriptor { 50 get { 51 return _controllerDescriptor; 52 } 53 } 54 55 public MethodInfo MethodInfo { 56 get; 57 private set; 58 } 59 60 public override string UniqueId { 61 get { 62 return _uniqueId.Value; 63 } 64 } 65 CreateUniqueId()66 private string CreateUniqueId() { 67 return base.UniqueId + DescriptorUtil.CreateUniqueId(MethodInfo); 68 } 69 Execute(ControllerContext controllerContext, IDictionary<string, object> parameters)70 public override object Execute(ControllerContext controllerContext, IDictionary<string, object> parameters) { 71 if (controllerContext == null) { 72 throw new ArgumentNullException("controllerContext"); 73 } 74 if (parameters == null) { 75 throw new ArgumentNullException("parameters"); 76 } 77 78 ParameterInfo[] parameterInfos = MethodInfo.GetParameters(); 79 var rawParameterValues = from parameterInfo in parameterInfos 80 select ExtractParameterFromDictionary(parameterInfo, parameters, MethodInfo); 81 object[] parametersArray = rawParameterValues.ToArray(); 82 83 ActionMethodDispatcher dispatcher = DispatcherCache.GetDispatcher(MethodInfo); 84 object actionReturnValue = dispatcher.Execute(controllerContext.Controller, parametersArray); 85 return actionReturnValue; 86 } 87 GetCustomAttributes(bool inherit)88 public override object[] GetCustomAttributes(bool inherit) { 89 return MethodInfo.GetCustomAttributes(inherit); 90 } 91 GetCustomAttributes(Type attributeType, bool inherit)92 public override object[] GetCustomAttributes(Type attributeType, bool inherit) { 93 return MethodInfo.GetCustomAttributes(attributeType, inherit); 94 } 95 GetFilterAttributes(bool useCache)96 internal override IEnumerable<FilterAttribute> GetFilterAttributes(bool useCache) { 97 if (useCache && GetType() == typeof(ReflectedActionDescriptor)) { 98 // Do not look at cache in types derived from this type because they might incorrectly implement GetCustomAttributes 99 return ReflectedAttributeCache.GetMethodFilterAttributes(MethodInfo); 100 } 101 return base.GetFilterAttributes(useCache); 102 } 103 GetParameters()104 public override ParameterDescriptor[] GetParameters() { 105 ParameterDescriptor[] parameters = LazilyFetchParametersCollection(); 106 107 // need to clone array so that user modifications aren't accidentally stored 108 return (ParameterDescriptor[])parameters.Clone(); 109 } 110 GetSelectors()111 public override ICollection<ActionSelector> GetSelectors() { 112 ActionMethodSelectorAttribute[] attrs = (ActionMethodSelectorAttribute[])MethodInfo.GetCustomAttributes(typeof(ActionMethodSelectorAttribute), true /* inherit */); 113 ActionSelector[] selectors = Array.ConvertAll(attrs, attr => (ActionSelector)(controllerContext => attr.IsValidForRequest(controllerContext, MethodInfo))); 114 return selectors; 115 } 116 IsDefined(Type attributeType, bool inherit)117 public override bool IsDefined(Type attributeType, bool inherit) { 118 return MethodInfo.IsDefined(attributeType, inherit); 119 } 120 LazilyFetchParametersCollection()121 private ParameterDescriptor[] LazilyFetchParametersCollection() { 122 return DescriptorUtil.LazilyFetchOrCreateDescriptors<ParameterInfo, ParameterDescriptor>( 123 ref _parametersCache /* cacheLocation */, 124 MethodInfo.GetParameters /* initializer */, 125 parameterInfo => new ReflectedParameterDescriptor(parameterInfo, this) /* converter */); 126 } 127 TryCreateDescriptor(MethodInfo methodInfo, string name, ControllerDescriptor controllerDescriptor)128 internal static ReflectedActionDescriptor TryCreateDescriptor(MethodInfo methodInfo, string name, ControllerDescriptor controllerDescriptor) { 129 ReflectedActionDescriptor descriptor = new ReflectedActionDescriptor(methodInfo, name, controllerDescriptor, false /* validateMethod */); 130 string failedMessage = VerifyActionMethodIsCallable(methodInfo); 131 return (failedMessage == null) ? descriptor : null; 132 } 133 } 134 } 135