首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > ASP >

asp.net mvc源码分析-RenderAction跟RenderPartial

2012-11-23 
asp.net mvc源码分析-RenderAction和RenderPartial截止上篇文章asp.net mvc源码分析-ActionResult篇 Razor

asp.net mvc源码分析-RenderAction和RenderPartial

截止上篇文章asp.net mvc源码分析-ActionResult篇 RazorView.RenderView 相信大家对mvc的大致流程应该有所了解。现在我们来看看我们在mvc开发中用的最多的几个方法,我想排在第一的应该是Html.RenderAction和Html.RenderPartial吧。先说简单的吧:RenderPartial和Partial

 public static void RenderPartial(this HtmlHelper htmlHelper, string partialViewName, object model, ViewDataDictionary viewData) {
            htmlHelper.RenderPartialInternal(partialViewName, viewData, model,htmlHelper.ViewContext.Writer, ViewEngines.Engines);
        }

  public static MvcHtmlString Partial(this HtmlHelper htmlHelper, string partialViewName, object model, ViewDataDictionary viewData) {
            using (StringWriter writer = new StringWriter(CultureInfo.CurrentCulture)) {
                htmlHelper.RenderPartialInternal(partialViewName, viewData, model,writer, ViewEngines.Engines);
                return MvcHtmlString.Create(writer.ToString());
            }
        }

从这里我们可以知道RenderPartial和Partial它们返回的东西写到的流不一致,一个是当前的writer,一个是新建的writer,当然新建的writer便于返回字符文本。

  internal virtual void RenderPartialInternal(string partialViewName, ViewDataDictionary viewData, object model, TextWriter writer, ViewEngineCollection viewEngineCollection) {
            if (String.IsNullOrEmpty(partialViewName)) {
                throw new ArgumentException(MvcResources.Common_NullOrEmpty, "partialViewName");
            }
            ViewDataDictionary newViewData = null;
            if (model == null) {
                if (viewData == null) {
                    newViewData = new ViewDataDictionary(ViewData);
                }
                else {
                    newViewData = new ViewDataDictionary(viewData);
                }
            }
            else {
                if (viewData == null) {
                    newViewData = new ViewDataDictionary(model);
                }
                else {
                    newViewData = new ViewDataDictionary(viewData) { Model = model };
                }
            }


            ViewContext newViewContext = new ViewContext(ViewContext, ViewContext.View, newViewData, ViewContext.TempData, writer);
            IView view = FindPartialView(newViewContext, partialViewName, viewEngineCollection);
            view.Render(newViewContext, writer);
        }

看看 是不是很简单,而这里的FindPartialView其实核心代码就一句,

      ViewEngineResult result = viewEngineCollection.FindPartialView(viewContext, partialViewName);我们从前面的文章中知道FindView 和FindPartialView的逻辑是一致的。

现在 我们来看看RenderAction和 Action方法

  public static MvcHtmlString Action(this HtmlHelper htmlHelper, string actionName, string controllerName, RouteValueDictionary routeValues) {
            using (StringWriter writer = new StringWriter(CultureInfo.CurrentCulture)) {
                ActionHelper(htmlHelper, actionName, controllerName, routeValues, writer);
                return MvcHtmlString.Create(writer.ToString());
            }
        }

  public static void RenderAction(this HtmlHelper htmlHelper, string actionName, string controllerName, RouteValueDictionary routeValues) {
            ActionHelper(htmlHelper, actionName, controllerName, routeValues, htmlHelper.ViewContext.Writer);
        }


可惜的是在mvc中没有使用这个VirtualPath属性,应为我们不需要从这里取值。真正取值是靠下面这句

  if (additionalRouteValues != null) {
                routeValues[ChildActionValueProvider.ChildActionValuesKey] = new DictionaryValueProvider<object>(additionalRouteValues, CultureInfo.InvariantCulture);

            }

这句 就是我们传进来的routeValues给保存起来,便于后面调用。

那么这里我们顺便看看ChildActionValueProvider的关键实现代码:

        public override ValueProviderResult GetValue(string key) {
            if (key == null) {
                throw new ArgumentNullException("key");
            }
            ValueProviderResult explicitValues = base.GetValue(ChildActionValuesKey);
            if (explicitValues != null) {
                DictionaryValueProvider<object> rawExplicitValues = explicitValues.RawValue as DictionaryValueProvider<object>;
                if (rawExplicitValues != null) {
                    return rawExplicitValues.GetValue(key);
                }
            }
            return null;
        }

先通过ChildActionValuesKey取得routeValues,再在routeValues中根据key来取值。我想大家看到这里就应该明白为什么RenderAction时DefaultModelBinder会走BindSimpleModel方法了吧,但是如果routeValues中并没有传递我们需要的参数,而我们的参数又是一个复杂类型那么就会走BindComplexModel方法,是简单类型就直接返回一个null,是否是简单类型是看起能否转换成string。

CreateRouteData这个方法没什么特别的,只是 routeData.DataTokens[ControllerContext.PARENT_ACTION_VIEWCONTEXT] = parentViewContext;把新的Action作为子Action。

HttpHandlerUtil.WrapForServerExecute这个方法没什么好说的,把当前ChildActionMvcHandler包装成一个ServerExecuteHttpHandlerWrapper,不过ServerExecuteHttpHandlerWrapper继承于Page类。

从 这里我们知道RenderAction是发起一个handler请求处理和RenderPartial只是呈现试图,所以RenderPartial的性能要高出很多。

热点排行