詳細看看InvokeAction方式的執行:
protected internal bool InvokeAction(string actionName) {
return InvokeAction (actionName, new RouteValueDictionary());
}
protected internal virtual bool InvokeAction(string actionName, RouteValueDictionary values) {
if (String.IsNullOrEmpty(actionName)) {
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
}
// We have to loop through all the methods to make sure there isn't
// a conflict. If we stop the loop the first time we find a match
// we might miss some error cases.
MemberInfo[] membInfos = GetType().GetMember(actionName, MemberTypes.Method,
BindingFlags.IgnoreCase | BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public);
MethodInfo foundMatch = null;
foreach (MemberInfo memberInfo in membInfos) {
MethodInfo mi = (MethodInfo)memberInfo;
// 1) Action methods must not have the non-action attribute in their inheritance chain, and
// 2) special methods like constructors, property accessors, and event accessors cannot be action methods, and
// 3) methods originally defined on Object (like ToString) or Controller cannot be action methods.
if (!mi.IsDefined(typeof(NonActionAttribute), true) &&
!mi.IsSpecialName &&
mi.DeclaringType.IsSubclassOf(typeof(Controller))) {
if (foundMatch != null) {
throw new InvalidOperationException(
String.Format(CultureInfo.CurrentUICulture, MvcResources.Controller_MoreThanOneAction, actionName, GetType()));
}
foundMatch = mi;
}
}
if (foundMatch != null) {
InvokeActionMethod(foundMatch, values);
return true;
}
return false;
}
它通過反射擷取所有同名 Action 方法信 息;其次,它過濾掉所有有 NonActionAttribute 和 IsSpecialName 標記的方法 ;第三,當同名有效 Action 被重載時它會拋出異常(提示 Controller_MoreThanOneAction),繼續調用InvokeActionMethod:
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters",
Justification = "We use MethodInfo since it represents only methods and not constructors." +
"This method only makes sense for use with methods.")]
protected internal virtual void InvokeActionMethod(MethodInfo methodInfo, RouteValueDictionary values) {
if (methodInfo == null) {
throw new ArgumentNullException("methodInfo");
}
if (values == null) {
values = new RouteValueDictionary();
}
if (methodInfo.ContainsGenericParameters) {
throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, MvcResources.Controller_ActionCannotBeGeneric, methodInfo.Name));
}
ParameterInfo[] methodParameters = methodInfo.GetParameters();
object[] parameterValues = null;
if (methodParameters.Length > 0) {
parameterValues = new object[methodParameters.Length];
for (int i = 0; i < methodParameters.Length; i++) {
ParameterInfo pi = methodParameters[i];
if (pi.IsOut || pi.ParameterType.IsByRef) {
throw new InvalidOperationException(String.Format (CultureInfo.CurrentUICulture, MvcResources.Controller_ReferenceParametersNotSupported, pi.Name, methodInfo.Name));
}
bool valueRequired = true;
if (pi.ParameterType.IsClass) {
// Classes (ref types) don't require values since we can pass in null
valueRequired = false;
}
else {
if ((pi.ParameterType.IsGenericType && ! pi.ParameterType.IsGenericTypeDefinition) &&
(pi.ParameterType.GetGenericTypeDefinition() == typeof (Nullable<>))) {
// Nullable types don't require values since we can pass in null
valueRequired = false;
}
}
// Try to get a value for the parameter. We use this order of precedence:
// 1. Explicitly-provided extra parameters in the call to InvokeAction()
// 2. Values from the RouteData (could be from the typed-in URL or from the route's default values)
// 3. Request values (query string, form post data, cookie)
object parameterValue = null;
if (!values.TryGetValue (methodParameters[i].Name, out parameterValue)) {
if (RouteData == null || !RouteData.Values.TryGetValue (methodParameters[i].Name, out parameterValue)) {
if (Request != null) {
parameterValue = Request[methodParameters[i].Name];
}
}
}
if (parameterValue == null && valueRequired) {
throw new InvalidOperationException(String.Format (CultureInfo.CurrentUICulture, MvcResources.Controller_MissingParameter, pi.Name, methodInfo.Name));
}
try {
parameterValues[i] = ConvertParameterType (parameterValue, methodParameters[i].ParameterType, methodParameters [i].Name, methodInfo.Name);
}
catch (Exception ex) {
// Parameter value conversion errors are acceptable unless the value is required
if (valueRequired) {
throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, MvcResources.Controller_MissingParameter, pi.Name, methodInfo.Name), ex);
}
}
}
}
InvokeActionMethodFilters(methodInfo, () => methodInfo.Invoke(this, parameterValues));
}