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