あなたをオープンソースに連れて行きます-ASP.NET_MVC(十一)


前編ではHtmlHelperについて述べましたが、今日はこの話題を続けます.
私たちは自分で作ったMVCプロジェクトの中で、勝手に1つ開けます.cshtmlファイル、HtmlHelper呼び出しを見つけます.たとえば:@Html.TextBox(「CustomerName」)は、Htmlにカーソルを置き、F 12を押してその定義に入ります.すなわち、コードセグメント1の文【public new HtmlHelperHtml{get;set;}].@HtmlはHtmlHelperクラスの一例であり、汎用クラスWebViewPageの属性であることがわかる.cshtmlファイルのクラスは汎用クラスWebViewPageに継承されているので、Razorで@Htmlを直接使用できます.
#region    System.Web.Mvc.dll, v4.0.30319
// C:\Program Files(x86)\Microsoft ASP.NET\ASP.NET MVC 4\Assemblies\System.Web.Mvc.dll
#endregion
 
using System;
 
namespace System.Web.Mvc
{
    //   :
    //           ASP.NET Razor              。
    //
    //     :
    //  TModel:
    //             。
    public abstract classWebViewPage<TModel> : WebViewPage
    {
        //   :
        //        System.Web.Mvc.WebViewPage<TModel>      。
        protected WebViewPage();
 
        //   :
        //          System.Web.Mvc.AjaxHelper   ,        Ajax    HTML   。
        //
        //     :
        //         AJAX    HTML    System.Web.Mvc.AjaxHelper   。
        public AjaxHelper<TModel> Ajax { get; set; }
        //
        //   :
        //          System.Web.Mvc.HtmlHelper   ,        HTML   。
        //
        //     :
        //         HTML     System.Web.Mvc.HtmlHelper   。
        public HtmlHelper<TModel> Html {get; set; }
        //
        //   :
        //          System.Web.Mvc.ViewDataDictionary     Model  。
        //
        //     :
        //        System.Web.Mvc.ViewDataDictionary     Model  。
        public TModel Model { get; }
        //
        //   :
        //             ,                  。
        //
        //     :
        //        ,                  。
        public ViewDataDictionary<TModel>ViewData { get; set; }
 
        //   :
        //        System.Web.Mvc.AjaxHelper、System.Web.Mvc.HtmlHelper  System.Web.Mvc.UrlHelper
        //     。
        public override void InitHelpers();
        //
        //   :
        //          。
        //
        //   :
        //  viewData:
        //        。
        protected override void SetViewData(ViewDataDictionaryviewData);
    }
}
コードセグメント1
では、汎用クラスHtmlHelperの定義(コードセグメント2)に入ります.ここでは、ViewDataとView Bagという2つの興味のある属性を見ることができます.そう、これは私たちが異なるHttpリクエスト間の状態を維持するために使用した2つのものです.
    public class HtmlHelper<TModel> :HtmlHelper
    {
        private DynamicViewDataDictionary_dynamicViewDataDictionary;
        privateViewDataDictionary<TModel> _viewData;
 
        public HtmlHelper(ViewContextviewContext, IViewDataContainer viewDataContainer)
            : this(viewContext,viewDataContainer, RouteTable.Routes)
        {
        }
 
        public HtmlHelper(ViewContextviewContext, IViewDataContainer viewDataContainer, RouteCollectionrouteCollection)
            : base(viewContext,viewDataContainer, routeCollection)
        {
            _viewData = new ViewDataDictionary<TModel>(viewDataContainer.ViewData);
        }
 
        public new dynamic ViewBag
        {
            get
            {
                if (_dynamicViewDataDictionary== null)
                {
                    _dynamicViewDataDictionary= new DynamicViewDataDictionary(() => ViewData);
                }
 
                return_dynamicViewDataDictionary;
            }
        }
 
        public newViewDataDictionary<TModel> ViewData
        {
            get { return _viewData; }
        }
    }
コードセグメント2
ViewDataとViewBag属性の定義にnewキーワードが使われているのを見てみましょう.これはなぜですか.キーワードnewは、オブジェクトの作成によく使用されるほか、親クラスの同名メンバーを上書きする役割もあることを知っています.このことから,汎用クラスHtmlHelperの親クラスにも必ずViewDataというメンバが存在することが分かる.(注:この記事の第2の自然セグメントの文【public newHtmlHelperHtml{get;set;}】そういう意味です.汎用クラスHtmlHelperの親クラスHtmlHelperに入ると、案の定、確かにViewDataプロパティとViewBagプロパティがあります.コードセグメント3を参照してください.ViewDataは辞書で、ViewBagはダイナミックタイプです.どうですか.これがViewDataとViewBagの廬山の正体です.
  
      public ViewDataDictionary ViewData
        {
            get { returnViewDataContainer.ViewData; }
        }
        public dynamic ViewBag
        {
            get
            {
                if (_dynamicViewDataDictionary== null)
                {
                    _dynamicViewDataDictionary= new DynamicViewDataDictionary(() => ViewData);
                }
                return _dynamicViewDataDictionary;
            }
        }
コードセグメント3
HtmlHelperクラスでは一般的なActionLink、TextBoxなどのHelperは見つかっていませんが、前回の記事でActionLinkについての分析を振り返ると、MVCフレームワークに内蔵されているHtmlHelperは拡張方法として定義されていることがわかります.これらの拡張方法はMVCソースコードの「System.Web.MVC/Html」パスの下に存在し、名前にExtentionが含まれているクラス、例えばInputExtensions、LabelExtensions、ChildActionExtensions、FormExtensions、NameExtensions、PartialExtensions、SelectExtensions、TextAreaExtensionsなど.
次に、FormExtensionsクラスについて再説明します.このクラスでは、よく使われる@Htmlを見つけることができます.BeginFormの定義、間違いなくRazorでWebフォームを定義するHelperです.このHelperを使ったことがある人なら誰でも気づくことですが、BeginFormの使い方は「@using(Html.BeginForm(){}」で、普通のHelperとは違います.この使い方はEndFormメソッドを呼び出さなくてもいいのですが、これはなぜですか?
USingキーワードを見ると、ここではコードブロックが終了する前にDisposeメソッドを自動的に呼び出す役割を果たしていることがわかります.もちろん、usingコードブロック内のオブジェクトはIDisposableインタフェースを実現しなければなりません.BeginFormの定義(コードセグメント4)を見つけ、このメソッドの戻り値がMvcFormオブジェクトであることを発見します.
        public static MvcForm BeginForm(thisHtmlHelper htmlHelper)
        {
            // generates <formaction="{current url}" method="post">...</form>
            string formAction =htmlHelper.ViewContext.HttpContext.Request.RawUrl;
            return FormHelper(htmlHelper, formAction,FormMethod.Post, new RouteValueDictionary());
        }
コードセグメント4
MvcFormクラスの定義を追跡すると、このクラスはやはりIDisposableインタフェースを実現し、狂喜していることがわかります.MvcFormクラスの定義で、Disposeメソッドの実装(コードセグメント5)を見つけて、おおらかでしょう?DisposeメソッドでFormExtensionsが呼び出された.EndFormメソッド.
        public void Dispose()
        {
            Dispose(true /* disposing */);
            GC.SuppressFinalize(this);
        }
 
        protected virtual void Dispose(booldisposing)
        {
            if (!_disposed)
            {
                _disposed = true;
                FormExtensions.EndForm(_viewContext);
            }
        }
コードセグメント5
続行EndFormメソッドの定義(コードセグメント6)は、よりおおらかでしょう?狂喜を続ける!EndFormメソッドの役割は、Webフォームの終了フラグをブラウザに送信することです.
        internal static voidEndForm(ViewContext viewContext)
        {
           viewContext.Writer.Write("</form>");
           viewContext.OutputClientValidation();
            viewContext.FormContext = null;
        }
コードセグメント6