MVC視圖中的@Html.xxx(...)


ASP.NET MVC視圖中的@Html.xxx(...)

 

問題

在視圖頁中@Html.xxx(...)是什么?如何被執行?

如下圖所示:
  

解疑

視圖頁中@Html.xxx(...)涉及的內容有:

  • 視圖頁被編譯后的類繼承自 WebViewPage<T>:WebViewPage:WebPageBase:WebPageRenderingBase:WebPageExecutingBase
  • 在進行View呈現過程中,創建視圖頁對象實例,此時 初始化了一個HtmlHelper對象,並賦值給其父類的一個名為Html的屬性,@Html.xxx(...)中的Html就是該屬性
  • 視圖頁中的@Html.xxx(...),經過編譯之后,則變成該視圖頁對象Execute方法中的一段代碼,即:this.Write(this.Html.xxx(xxx));
  • xxx是HtmlHelper類的擴展方法

以@Html.TextBox(...)為例進行詳細分析:

  在ASP.NET MVC 中,視圖頁都被編譯成繼承自WebViewPage<T>的類,而在進行 View呈現 的過程中,需要通過反射創建視圖頁類的實例(Object類型),然后再將該實例轉換為WebViewPage類型,並進行一些初始化操作,就在初始化時,創建了HtmlHelper對象,並賦值給其屬性Html。

復制代碼
public abstract class BuildManagerCompiledView : IView
{
    public void Render(ViewContext viewContext, TextWriter writer)
    {
        if (viewContext == null)
        {
            throw new ArgumentNullException("viewContext");
        }
 
        object instance = null;
        //獲取被編譯的視圖頁(cshtml文件)的類型                                                                 
        Type type = BuildManager.GetCompiledType(ViewPath);
        if (type != null)
        {
            //通過SingleServiceResolver利用反射和緩存的原理創建視圖頁的實例,過程類似SingleServiceResolver類對Controller的激活。
            instance = ViewPageActivator.Create(_controllerContext, type);
        }
 
        if (instance == null)
        {
            throw new InvalidOperationException(
                String.Format(
                    CultureInfo.CurrentCulture,
                    MvcResources.CshtmlView_ViewCouldNotBeCreated,
                    ViewPath));
        }
        //執行RenderView方法
        RenderView(viewContext, writer, instance);
    }
}
public class RazorView : BuildManagerCompiledView
{
    protected override void RenderView(ViewContext viewContext, TextWriter writer, object instance)
    {
        if (writer == null)
        {
            throw new ArgumentNullException("writer");
        }
        //將視圖頁實例轉換為WebViewPage對象。
        WebViewPage webViewPage = instance as WebViewPage;
        if (webViewPage == null)
        {
            throw new InvalidOperationException(
                String.Format(
                    CultureInfo.CurrentCulture,
                    MvcResources.CshtmlView_WrongViewBase,
                    ViewPath));
        }
        webViewPage.OverridenLayoutPath = LayoutPath;//母板路徑(在第二步中,創建RazorView對象時,由構造函數導入)
        webViewPage.VirtualPath = ViewPath;          //該視圖路徑
        webViewPage.ViewContext = viewContext;       //視圖上下文,其中有TempData、controllerContext、ViewData等
        webViewPage.ViewData = viewContext.ViewData;
        
        //WebViewPage對象初始化,執行創建3個xxHelper對象AjaxHelper、HtmlHelper、UrlHelper。
        webViewPage.InitHelpers();
 
        if (VirtualPathFactory != null)
        {
            webViewPage.VirtualPathFactory = VirtualPathFactory;
        }
        if (DisplayModeProvider != null)
        {
            webViewPage.DisplayModeProvider = DisplayModeProvider;
        }
 
        WebPageRenderingBase startPage = null;
        if (RunViewStartPages)
        {
            startPage = StartPageLookup(webViewPage, RazorViewEngine.ViewStartFileName, ViewStartFileExtensions);
        }
        //按層次結構處理視圖頁的內容。
        webViewPage.ExecutePageHierarchy(new WebPageContext(context: viewContext.HttpContext, page: null, model: null), writer, startPage);
    }
}
復制代碼
復制代碼
public abstract class WebViewPage : WebPageBase, IViewDataContainer, IViewStartPageChild
{
    //省略其他代碼...
    public AjaxHelper<object> Ajax
    {
        get;
        set;
    }
    
    public HtmlHelper<object> Html
    {
        get;
        set;
    }
    
    public UrlHelper Url
    {
        get;
        set;
    }
    
    public ViewContext ViewContext
    {
        get;
        set;
    }
    
    public virtual void InitHelpers()
    {
        this.Ajax = new AjaxHelper<object>(this.ViewContext, this);
        this.Html = new HtmlHelper<object>(this.ViewContext, this);
        this.Url = new UrlHelper(this.ViewContext.RequestContext);
    }
}
復制代碼

 “_Index.cshtml”經編譯后的結果為:

  如上圖所示,“@Html.TextBox(‘txtUser’)” 經過編譯后,就是去執行base.Html.TextBox("txtUser"),又由類繼承關系可知,base.Html的值就是一個HtmlHelper對象(視圖頁對象轉換為WebViewPage類型后,初始化時創建的)。而TextBox("txtUser"),則是HtmlHelper的擴展方法!

  InputExtensions

  代碼中,TextBox等擴展方法最終調用InputHelper方法,從而生成對應字符串類型的html標簽(如:<input type='text"...>),然后將標簽封裝到一個MvcHtmlString對象中,並返回。即:base.Html.TextBox("txtUser")的執行結果就是一個封裝了html標簽內容的MvcHtmlString對象。之后執行this.Write(base.Html.TextBox("txtUser"))時,會執行MvcHtmlString對象的 ToHtmlString()方法獲取html標簽,最終將標簽內容寫入到響應給客戶端的內容中!

  IHtmlString
  HtmlString
  MvcHtmlString

 以下展示如何從MmvHtmlString對象中得到被封裝的html標簽(如:<input type='text"...>),並寫入到Http響應內容中!

 最終,將生成的html標簽以字符串的形式寫入到Http響應內容中!

 以上只對HtmlHelper的擴展方法TextBox進行了介紹,其他的擴展方法童鞋們自行補腦了!上述如有不適之處,請指正!!!

擴展:

  可以通過創建一個HtmlHelper的擴展方法,從而實現一個自定義控件!

 
 
分類:  MVC
標簽:  ASP.NET MVC


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM