asp.net mvc源碼分析-Action篇 Action的執行

來源:互聯網
上載者:User

接著上篇 asp.net mvc源碼分析-Action篇 DefaultModelBinder 我們已經擷取的了Action的參數,有前面的內容我們知道Action的調用時在ControllerActionInvoker類的InvokeActionMethod方法。

 protected virtual ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters) {
            object returnValue = actionDescriptor.Execute(controllerContext, parameters);
            ActionResult result = CreateActionResult(controllerContext, actionDescriptor, returnValue);
            return result;
        }

我們現在知道actionDescriptor是ReflectedActionDescriptor類的一個執行個體,

ReflectedActionDescriptor的Execute方法的實現大致如下

        public override object Execute(ControllerContext controllerContext, IDictionary<string, object> parameters) {
            ParameterInfo[] parameterInfos = MethodInfo.GetParameters();
           var rawParameterValues = from parameterInfo in parameterInfos
                                     select ExtractParameterFromDictionary(parameterInfo, parameters, MethodInfo);
            object[] parametersArray = rawParameterValues.ToArray();
            ActionMethodDispatcher dispatcher = DispatcherCache.GetDispatcher(MethodInfo);
            object actionReturnValue = dispatcher.Execute(controllerContext.Controller, parametersArray);
            return actionReturnValue;
        }

ParameterInfo[] parameterInfos = MethodInfo.GetParameters();這句沒什麼說的就是擷取Action的參數集合,大家應該知道方法參數中的parameters是什麼東西吧,一個以Action參數名為key,其值為value的一個字典結合。

var rawParameterValues = from parameterInfo in parameterInfos
                                     select ExtractParameterFromDictionary(parameterInfo, parameters, MethodInfo);
            object[] parametersArray = rawParameterValues.ToArray();

這兩句其實就是把parameters中參數value 按照Action中參數順序組成一個數組。ExtractParameterFromDictionary方法就是檢查parameters中的資料有效性。主要檢查parameters是否包含parameterInfo.Name,沒有拋異常,有則檢查是否為null,為null是就檢查 該參數是否允許為null,不允許則拋異常,不為null則檢查值是否是參數類型的一個執行個體。

ActionMethodDispatcherCache實現如下:

  internal sealed class ActionMethodDispatcherCache : ReaderWriterCache<MethodInfo,ActionMethodDispatcher> {
        public ActionMethodDispatcherCache() {}
        public ActionMethodDispatcher GetDispatcher(MethodInfo methodInfo) {
            return FetchOrCreateItem(methodInfo, () => new ActionMethodDispatcher(methodInfo));
        }
    }

這裡 的FetchOrCreateItem我們就不說,在ActionMethodDispatcherCache類是曾經說過。這裡的GetDispatcher其實是返回的ActionMethodDispatcher類的一個執行個體。

  public ActionMethodDispatcher(MethodInfo methodInfo) {
            _executor = GetExecutor(methodInfo);
            MethodInfo = methodInfo;
        }

其中 GetExecutor代碼如下:

 private static ActionExecutor GetExecutor(MethodInfo methodInfo) {            // Parameters to executor            ParameterExpression controllerParameter = Expression.Parameter(typeof(ControllerBase), "controller");            ParameterExpression parametersParameter = Expression.Parameter(typeof(object[]), "parameters");            // Build parameter list            List<Expression> parameters = new List<Expression>();            ParameterInfo[] paramInfos = methodInfo.GetParameters();            for (int i = 0; i < paramInfos.Length; i++) {                ParameterInfo paramInfo = paramInfos[i];                BinaryExpression valueObj = Expression.ArrayIndex(parametersParameter, Expression.Constant(i));                UnaryExpression valueCast = Expression.Convert(valueObj, paramInfo.ParameterType);                // valueCast is "(Ti) parameters[i]"                parameters.Add(valueCast);            }            // Call method            UnaryExpression instanceCast = (!methodInfo.IsStatic) ? Expression.Convert(controllerParameter, methodInfo.ReflectedType) : null;            MethodCallExpression methodCall = methodCall = Expression.Call(instanceCast, methodInfo, parameters);            // methodCall is "((TController) controller) method((T0) parameters[0], (T1) parameters[1], ...)"            // Create function            if (methodCall.Type == typeof(void)) {                Expression<VoidActionExecutor> lambda = Expression.Lambda<VoidActionExecutor>(methodCall, controllerParameter, parametersParameter);                VoidActionExecutor voidExecutor = lambda.Compile();                return WrapVoidAction(voidExecutor);            }            else {                // must coerce methodCall to match ActionExecutor signature                UnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object));                Expression<ActionExecutor> lambda = Expression.Lambda<ActionExecutor>(castMethodCall, controllerParameter, parametersParameter);                return lambda.Compile();            }        }

  其實這段代碼是很好理解的,就是用運算式樹狀架構來產生一個Action方法的調用。這段代碼最後返回的是一個ActionExecutor的委託,在這個GetExecutor方法中有一句很耗時的是
lambda.Compile(),大家想過這裡為什麼要用運算式樹狀架構而不直接調用MethodInfo的Invoke方法嗎?,調用Invoke方其實也很慢,最主要是調用過程是沒法緩衝的;而用運算式雖然編譯成委託時要慢點,但是這裡有一個ActionMethodDispatcherCache來保證每個Action調用所需的委託執行個體只需編譯一次,多次調用同一Action運算式就比Invoke方法效能高多了。看見微軟在mvc3中緩衝做的已經很好了。

object actionReturnValue = dispatcher.Execute(controllerContext.Controller, parametersArray);這句就是調用_executor委託,也就是真正執行Action方法,actionReturnValue 就是Action的傳回值,預設是一個ActionResult。

現在 再來看看  ActionResult result = CreateActionResult(controllerContext, actionDescriptor, returnValue);這個方法吧:

 protected virtual ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue) {
            if (actionReturnValue == null) {
                return new EmptyResult();
            }

            ActionResult actionResult = (actionReturnValue as ActionResult) ??
                new ContentResult { Content = Convert.ToString(actionReturnValue, CultureInfo.InvariantCulture) };
            return actionResult;
        }

ActionResult actionResult = (actionReturnValue as ActionResult) ??new ContentResult { Content = Convert.ToString(actionReturnValue, CultureInfo.InvariantCulture) };就是 檢查Action返回的是否是一個ActionResult,正常境況下都是的。如果返回的不是則構造一個ContentResult 返回,我在想如果Action返回的不是ActionResult,我們throw是不是更好了。

如 我們的Action如下

  public class HomeController : Controller
    {
        public object Index(){return new  { Name="majiang"};}
    }

返回結果:

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.