Take a detailed look at the execution of the Invokeaction method:
protected internal bool Invokeaction (string actionname) {
return invokeaction (ActionName, New routevalued Ictionary ());
}
Protected internal virtual bool Invokeaction (string actionname, routevaluedictionary values) {
if (String.IsNullOrEmpty (ActionName)) {
throw new ArgumentException (Mvcresources.common_nullorempty, "actio Nname ");
}
//We have to loop through all the methods to make sure there isn ' t
/a conflict. If we stop the loop the "the" 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 acces Sors, and event accessors cannot to action methods, and
//3) methods originally defined on Object (like Tostr ing) or Controller cannot be action methods.
if (!mi. IsDefined (typeof (Nonactionattribute), true) &&
!mi. Isspecialname &&
mi. Declaringtype.issubclassof (typeof (Controller))) {
if (foundmatch!= null) {
throw new inval Idoperationexception (
String.Format cultureinfo.currentuiculture, MVCRESOURCES.CONTROLLER_MORETHANONEAC tion, ActionName, GetType ()));
}
Foundmatch = mi;
}
if (Foundmatch!= null) {
Invokeactionmethod (Foundmatch, values);
return true;
}
return false;
}
It obtains all Action method information of the same name by reflection, and secondly, it filters out all methods with Nonactionattribute and isspecialname tags; third, it throws an exception when a valid Action of the same name is overloaded (prompt controller_mo Rethanoneaction), continue to invoke Invokeactionmethod:
[SuppressMessage ("Microsoft.Design", "CA1011: Considerpassingbasetypesasparameters ",
justification = "We use MethodInfo since it represents only methods and not constructors." +
"This method is only makes sense to 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_re ferenceparametersnotsupported, 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 to 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_m Issingparameter, 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_m Issingparameter, Pi. Name, Methodinfo.name), ex);
}
}
}
}
invokeactionmethodfilters (MethodInfo, () => Methodinfo.invoke (this, parametervalues));
}