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


前編ではActionResultのExecuteResultメソッドについてお話ししましたが、今日は続きます.
まずActionResultの定義(コードセグメント1)を見てみましょう.抽象クラスであり、ExecuteResultの抽象メソッドは1つしかありません.
    public abstract class ActionResult
    {
        public abstract voidExecuteResult(ControllerContext context);
    }

コードセグメント1
ActionResultは重要な話題であり、MVCはActionでHTML応答を直接生成して返信するのではなく、ActionResultを返し、MVCフレームワークでExecuteResultメソッドを呼び出す.これは、提案要求と実行要求を分離し、それらの間の結合を解除する設計モードの応用である「コマンドモード」である.コマンドモードについては、自分で度娘脳補を探してください.
ActionResultには、ViewResultBase、ContentResult、FileResult、HttpStatusCodeResult、JavaScriptResult、JsonResult、RedirectResult、RedirectToRouteResult、AtomEnttryActionResult、AtomFeedActionResult、AtomServiceDocumentActionResult、DataContractJsonActionResult、DataContractXmlActionResult、MultiiFormatActionResult、ResourcceResourceResult ErrorActionResult,ResourceRedirectToRouteResult.これらのサブクラスはすべて異なるニーズに対して定義されており、最も一般的なのはViewResultBaseのサブクラスViewResultです(もちろん、PartialViewResultもViewResultBaseのサブクラスです).ただし、ViewResultはExecuteResultメソッドを書き換えるのではなく、親のViewResultBaseによる書き換えです.コードセグメント2を参照してください.
        public override voidExecuteResult(ControllerContext context)
        {
            if (context == null)
            {
                throw newArgumentNullException("context");
            }
            if (String.IsNullOrEmpty(ViewName))
            {
                ViewName =context.RouteData.GetRequiredString("action");
            }
 
            ViewEngineResult result = null;
 
            if (View == null)
            {
                result = FindView(context);
                View = result.View;
            }
 
            TextWriter writer =context.HttpContext.Response.Output;
            ViewContext viewContext = newViewContext(context, View, ViewData, TempData, writer);
            View.Render(viewContext, writer);
 
            if (result != null)
            {
               result.ViewEngine.ReleaseView(context, View);
            }
        }

コードセグメント2
コードセグメント2の文【View.Renderer(viewContext,writer)】は、HTMLをレンダリングしてブラウザに戻すコアコードです.ここでは万人が敬慕するビューエンジンのメカニズムを導入し始め、文「result=FindView(context)」を見て、FindViewの定義を追跡します.ああ、抽象的な方法です.いいでしょう.彼のサブクラスView Resultで探してください.コードセグメント3を参照してください.
        protected override ViewEngineResultFindView(ControllerContext context)
        {
            ViewEngineResult result =ViewEngineCollection.FindView(context, ViewName, MasterName);
            if (result.View != null)
            {
                return result;
            }
 
            // we need to generate an exceptioncontaining all the locations we searched
            StringBuilder locationsText = newStringBuilder();
            foreach (string location inresult.SearchedLocations)
            {
                locationsText.AppendLine();
                locationsText.Append(location);
            }
            throw newInvalidOperationException(String.Format(CultureInfo.CurrentCulture,
                                                             MvcResources.Common_ViewNotFound, ViewName, locationsText));
        }

コードセグメント3
FindViewメソッドの役割は、指定されたビューエンジンを見つけることであり、コードセグメント3において文【ViewEngineResult result=ViewEngineCollection.FindView(context,ViewName,MasterName)】を見つけ、ViewEngineCollectionにトレースすることである.FindViewの定義(コードセグメント4).
        public virtual ViewEngineResultFindView(ControllerContext controllerContext, string viewName, stringmasterName)
        {
            if (controllerContext == null)
            {
                throw newArgumentNullException("controllerContext");
            }
            if (String.IsNullOrEmpty(viewName))
            {
                throw newArgumentException(MvcResources.Common_NullOrEmpty, "viewName");
            }
 
            return Find(e =>e.FindView(controllerContext, viewName, masterName, true),
                        e =>e.FindView(controllerContext, viewName, masterName, false));
        }

コードセグメント4
現在使用されているビューエンジンを検索するためにFunclookupという依頼を使用するFindメソッド(コードセグメント5)へのトレース.
 
       private ViewEngineResultFind(Func<IViewEngine, ViewEngineResult> lookup, bool trackSearchedPaths)
        {
            // Returns
            //    1st result
            // OR list of searched paths (iftrackSearchedPaths == true)
            // OR null
            ViewEngineResult result;
 
            List<string> searched = null;
            if (trackSearchedPaths)
            {
                searched = newList<string>();
            }
 
            foreach (IViewEngine engine inCombinedItems)
            {
                if (engine != null)
                {
                    result = lookup(engine);
 
                    if (result.View != null)
                    {
                        return result;
                    }
 
                    if (trackSearchedPaths)
                    {
                       searched.AddRange(result.SearchedLocations);
                    }
                }
            }
 
            if (trackSearchedPaths)
            {
                // Remove duplicate searchpaths since multiple view engines could have potentially looked at the samepath
                return newViewEngineResult(searched.Distinct().ToList());
            }
            else
            {
                return null;
            }
        }

コードセグメント5
コードセグメント5には、ビューエンジンの集合を表すCombinedItemsがあり、その定義はコードセグメント6を参照してください.
        internal IViewEngine[] CombinedItems
        {
            get
            {
                IViewEngine[] combinedItems =_combinedItems;
                if (combinedItems == null)
                {
                    combinedItems =MultiServiceResolver.GetCombined<IViewEngine>(Items, _dependencyResolver);
                    _combinedItems =combinedItems;
                }
                return combinedItems;
            }
        }

コードセグメント6
CombinedItemsは実際にはViewEngineCollectionのコンテンツ項目を指していますが、ViewEngineCollectionのコンテンツはどこに埋め込まれていますか?コードセグメント3の「ViewEngineResult result=ViewEngineCollection.FindView(context,ViewName,MasterName)」を見てみましょう.その定義に移動します.コードセグメント7を参照してください.
        [SuppressMessage("Microsoft.Usage","CA2227:CollectionPropertiesShouldBeReadOnly", Justification ="This entire type is meant to be mutable.")]
        public ViewEngineCollectionViewEngineCollection
        {
            get { return _viewEngineCollection?? ViewEngines.Engines; }
            set { _viewEngineCollection =value; }
        }

コードセグメント7
ViewEngineCollectionはViewEnginesから来ていることがわかります.Engines、次にView Enginesに移動します.Enginesの定義は、コードセグメント8を参照してください.見たでしょ!秘密はここにある.ViewEngineCollectionという集合の内容は、予め設定されたWebFormViewEngineとRazorViewEngine、つまり私たちがよく知っているWebFormビューエンジンとRazorビューエンジンである.
    public static class ViewEngines
    {
        private static readonlyViewEngineCollection _engines = new ViewEngineCollection
        {
            new WebFormViewEngine(),
            new RazorViewEngine(),
        };
 
        public static ViewEngineCollectionEngines
        {
            get { return _engines; }
        }
}

コードセグメント8
コードセグメント4をもう一度見ると、「e=>e.FindView(controllerContext,viewName,masterName,true)」というLamda式(本質は依頼)がFindメソッドの最初のパラメータlookupとして伝達されていることがわかります.つまり、このLamda式は、あるビューエンジンが現在使用されているかどうかを判断するビューエンジンです.e.FindViewを追跡し続け、その定義(コードセグメント9)に入ると、FindViewはインタフェースIViewEngineの1つの方法であることが分かった.IViewEngineはビューエンジンのインタフェースで、私たちはすでにビューエンジンの核心に着いて、鶏は凍っていますか?
    public interface IViewEngine
    {
        ViewEngineResultFindPartialView(ControllerContext controllerContext, string partialViewName,bool useCache);
        ViewEngineResultFindView(ControllerContext controllerContext, string viewName, stringmasterName, bool useCache);
        void ReleaseView(ControllerContextcontrollerContext, IView view);
}

コードセグメント9
では、誰がIViewEngineインタフェースを実現したかを見てみましょう.半日探してみると、VirtualPathProviderView EngineだけがIViewEngineインタフェースを実現していることがわかりました.コードセグメント10を参照してください.
        public virtual ViewEngineResultFindView(ControllerContext controllerContext, string viewName, stringmasterName, bool useCache)
        {
            if (controllerContext == null)
            {
                throw newArgumentNullException("controllerContext");
            }
            if (String.IsNullOrEmpty(viewName))
            {
                throw newArgumentException(MvcResources.Common_NullOrEmpty, "viewName");
            }
 
            string[] viewLocationsSearched;
            string[] masterLocationsSearched;
 
            string controllerName =controllerContext.RouteData.GetRequiredString("controller");
            string viewPath =GetPath(controllerContext, ViewLocationFormats, AreaViewLocationFormats,"ViewLocationFormats", viewName, controllerName, CacheKeyPrefixView,useCache, out viewLocationsSearched);
            string masterPath =GetPath(controllerContext, MasterLocationFormats, AreaMasterLocationFormats,"MasterLocationFormats", masterName, controllerName,CacheKeyPrefixMaster, useCache, out masterLocationsSearched);
 
            if (String.IsNullOrEmpty(viewPath)|| (String.IsNullOrEmpty(masterPath) &&!String.IsNullOrEmpty(masterName)))
            {
                return newViewEngineResult(viewLocationsSearched.Union(masterLocationsSearched));
            }
 
            return newViewEngineResult(CreateView(controllerContext, viewPath, masterPath), this);
        }

コードセグメント10
CreateViewメソッドを追跡して抽象的なメソッドであることを発見しましたここではRazorViewのCreateViewメソッド書き換え(コードセグメント11)のみを見る.
        protected override IViewCreateView(ControllerContext controllerContext, string viewPath, stringmasterPath)
        {
            var view = new RazorView(controllerContext,viewPath,
                                    layoutPath: masterPath, runViewStartPages: true,viewStartFileExtensions: FileExtensions, viewPageActivator: ViewPageActivator)
            {
                DisplayModeProvider = DisplayModeProvider
            };
            return view;
        }

コードセグメント11
コードセグメント11はIViewオブジェクトを取得し、さらにコードセグメント10にViewEngineResultを取得させ、コードセグメント2の文「result=FindView(context);View=result.View;」に移動する.これにより、Viewオブジェクトが得られ、Viewが呼び出されます.Render(viewContext,writer)メソッド、その中のwriterは何ですか?「TextWriter writer=context.HttpContext.Response.Output;」という文を見つけました.おおらかですか.私たちが久しぶりに考えたResponseがついに現れ、それがあれば、HTML応答をブラウザにレンダリングして送り返すことができます.これで、ブラウザからHTTP要求を出して、サーバーにHTML応答を送り返して、完全な回路を構成して、大きな成果を収めました.私は頼りにして、疲れました!
未完待续..