2013年7月23日 星期二

ASP.NET MVC - Html.Partial 與 Html.RenderPartial

相信很多人都被 Html.Partial 與 Html.RenderPartial 這兩個給搞糊塗(另一組則是 Html.Action 與 Html.RenderAction,還有 ViewResult 以及 PartialViewResult),這邊就簡單說明一下 Html.Partial 與 Html.RenderPartial 的區別。

 


PartialExtensions 類別

http://msdn.microsoft.com/zh-tw/library/system.web.mvc.html.partialextensions(v=vs.108).aspx

代表可以將部分檢視轉譯為 HTML 編碼字串的功能。

使用 Html.Partial 的回傳是 MvcHtmlString 的結果,基本常用的使用方式如下:

image

PartialViewName 如果是與主頁面(例如 Index.cshtml)是同一個目錄,則可以直接填入 PartialViewName,而如果是使用其他目錄(例如 ~/Views/Shared/)的 Partial View 檔案,則可以使用檔案路徑。

PartialExtensions.cs 原始碼:

public static class PartialExtensions
{
    public static MvcHtmlString Partial(this HtmlHelper htmlHelper, string partialViewName)
    {
        return Partial(htmlHelper, partialViewName, null /* model */, htmlHelper.ViewData);
    }
 
    public static MvcHtmlString Partial(this HtmlHelper htmlHelper, string partialViewName, ViewDataDictionary viewData)
    {
        return Partial(htmlHelper, partialViewName, null /* model */, viewData);
    }
 
    public static MvcHtmlString Partial(this HtmlHelper htmlHelper, string partialViewName, object model)
    {
        return Partial(htmlHelper, partialViewName, model, htmlHelper.ViewData);
    }
 
    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());
        }
    }
}

由原始碼可以看到最後是輸出 MvcHtmlString 的結果。

 

RenderPartialExtensions 類別

http://msdn.microsoft.com/zh-tw/library/system.web.mvc.html.renderpartialextensions(v=vs.108).aspx

提供呈現部分檢視的支援。(這個敘述實在讓人摸不著頭緒)

依據「ASP.net MVC 4 網站開發美學」Page 5-89 關於 RenderPartial 的敘述,RenderPartial 是將結果直接寫入 ViewPage 的 Output Stream。

基本的使用方法如下:

image

用法跟 Html.Partial 一樣,PartialViewName 如果是與主頁面(例如 Index.cshtml)是同一個目錄,則可以直接填入 PartialViewName,而如果是使用其他目錄(例如 ~/Views/Shared/)的 Partial View 檔案,則可以使用檔案路徑。

RenderPartialExtensions.cs 原始碼:

public static class RenderPartialExtensions
{
    // Renders the partial view with the parent's view data and model
    public static void RenderPartial(this HtmlHelper htmlHelper, string partialViewName)
    {
        htmlHelper.RenderPartialInternal(partialViewName, htmlHelper.ViewData, null /* model */, htmlHelper.ViewContext.Writer, ViewEngines.Engines);
    }
 
    // Renders the partial view with the given view data and, implicitly, the given view data's model
    public static void RenderPartial(this HtmlHelper htmlHelper, string partialViewName, ViewDataDictionary viewData)
    {
        htmlHelper.RenderPartialInternal(partialViewName, viewData, null /* model */, htmlHelper.ViewContext.Writer, ViewEngines.Engines);
    }
 
    // Renders the partial view with an empty view data and the given model
    public static void RenderPartial(this HtmlHelper htmlHelper, string partialViewName, object model)
    {
        htmlHelper.RenderPartialInternal(partialViewName, htmlHelper.ViewData, model, htmlHelper.ViewContext.Writer, ViewEngines.Engines);
    }
 
    // Renders the partial view with a copy of the given view data plus the given model
    public static void RenderPartial(this HtmlHelper htmlHelper, string partialViewName, object model, ViewDataDictionary viewData)
    {
        htmlHelper.RenderPartialInternal(partialViewName, viewData, model, htmlHelper.ViewContext.Writer, ViewEngines.Engines);
    }
}

在原始碼裡可以看到與 PartialExtensions 不同的是,這邊的 Methods 都是沒有回傳結果,而是最後去執行 HtmlHelper.RenderPartialInternal() 方法,原始碼如下:

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);
}

 

基本上 Html.Partial 與 Html.RenderPartial 是一樣的,在 Profession ASP.NET MVC 4 裡面有提到,以編輯的方便性來說,建議使用 Html.Partial,因為在 View 使用 Html.RenderPartial 時必須用大括號來包住,如下圖所示:

image

而 Html.Partial 則不需要用大括號,如下圖:

image

兩者於其他使用情境上的比較:

image

在 Profession ASP.NET MVC 4 裡面另外有提到,若是以效能來說, Html.RenderPartial 會比 Html.Partial 來得好些,因為是在內部直接寫入到 ViewPage 的 Output Stream 裡,而 Html.Partial  則因為輸出 MvcHtmlString, ViewPage 於 Render 時會需要另外去處理。

 

在實務應用上要採用哪一種方法,因為兩者最後所呈現的結果是一樣的,內部也一樣使用了 HtmlHelper.RenderPartialInternal 方法,只是在輸出方式有所不同,所以要用哪一種就看開發者或是開發團隊的習慣、規則而定,如果很看種效能的表現而不在意開發時需要多敲幾下鍵盤,那就使用 Html.RenderPartial 方法。

我是習慣使用 Html.Partial 居多。

 

以上

3 則留言:

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。