• [ASP.NET MVC]视图是如何呈现的 (续)


    在上一篇文章中,我们知道了通过Controller执行ActionResult的Execute可以找到对应Controler对应的ViewEngine,然后在View中把Action的结果显示出来。那么ViewEngine到底是如何工作的?

    我们首先从ViewReult的FindView方法开始

    protectedoverrideViewEngineResult FindView(ControllerContext context)

    {

    ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName);

    if (result.View != null)

    {

    return result;

    }

    // we need to generate an exception containing all the locations we searched

    }

    根据ControllerContext和ViewName,以及MasterName找到对应的ViewEngineResult对象。我们还是以HelloController和Index为例。那么这里result将返回Views/Hello/Index.cshtml编译后的实例。我们进入FindView方法,看看其具体的实现。

    上述方法调用的是ViewEngineCollection类的虚方法FindView

    publicvirtualViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName)

    {

    if (controllerContext == null)

    {

    thrownewArgumentNullException("controllerContext");

    }

    if (String.IsNullOrEmpty(viewName))

    {

    thrownewArgumentException(MvcResources.Common_NullOrEmpty, "viewName");

    }

     

    return Find(e => e.FindView(controllerContext, viewName, masterName, true),

    e => e.FindView(controllerContext, viewName, masterName, false));

    }

    它又调用其私有的方法

    privateViewEngineResult Find(Func<IViewEngine, ViewEngineResult> cacheLocator, Func<IViewEngine, ViewEngineResult> locator)

    {

    // First, look up using the cacheLocator and do not track the searched paths in non-matching view engines

    // Then, look up using the normal locator and track the searched paths so that an error view engine can be returned

    return Find(cacheLocator, trackSearchedPaths: false)

    ?? Find(locator, trackSearchedPaths: true);

    }

    然后又调用

    privateViewEngineResult Find(Func<IViewEngine, ViewEngineResult> lookup, bool trackSearchedPaths)

    {

    // Returns

    // 1st result

    // OR list of searched paths (if trackSearchedPaths == true)

    // OR null

    ViewEngineResult result;

     

    List<string> searched = null;

    if (trackSearchedPaths)

    {

    searched = newList<string>();

    }

     

    foreach (IViewEngine engine in CombinedItems)

    {

    if (engine != null)

    {

    result = lookup(engine);

     

    if (result.View != null)

    {

    return result;

    }

     

    if (trackSearchedPaths)

    {

    searched.AddRange(result.SearchedLocations);

    }

    }

    }

     

    if (trackSearchedPaths)

    {

    // Remove duplicate search paths since multiple view engines could have potentially looked at the same path

    returnnewViewEngineResult(searched.Distinct().ToList());

    }

    else

    {

    returnnull;

    }

    }

     

     

    注意,这里传入了一个Func<IViewEngine, ViewEngineResult>。输入一个IViewEngine类型,请注意ViewEngine是实际来自ViewEnglieCollection的属性CombinedItems。该对象来自IResolver<IEnumerable<IViewEngine>>接口的Current属性,其类型为IEnuerable<IViewEngine>。其实就是传入一个IViewEngine,然后一个ViewEngileResult。比如下面的例子:

    // details of ViewEngineCollection.Find(*)

    Func<IViewEngine, System.Web.Mvc.ViewEngineResult> cacheLocator = e => e.FindView(ControllerContext, "ViewInstance", "", false);

    IViewEngine razorViewEngine = newRazorViewEngine();

    System.Web.Mvc.ViewEngineResult result = cacheLocator(razorViewEngine);

     

    请注意,IResolver<IEnumerable<IViewEngine>>的默认实例是newMultiServiceResolver<IViewEngine>(() => Items); 【有待于确认】。我们查看其构造函数,可以发现

    public MultiServiceResolver(Func<IEnumerable<TService>> itemsThunk)

    {

    if (itemsThunk == null)

    {

    thrownewArgumentNullException("itemsThunk");

    }

     

    _itemsThunk = itemsThunk;

    _resolverThunk = () => DependencyResolver.Current;

    _itemsFromService = newLazy<IEnumerable<TService>>(() => _resolverThunk().GetServices<TService>());

    }

     

    也就是说IResolver的实例来自DependencyResolver.Current。通过DependencyResolver的定义,我们得知Current属性返回的单列new DenpendencyResolver.InnerCurrent,InnerCurrent其实就是newDefaultDependencyResolver()DedendencyResolver在创建,创建单列的DefaultDependencyResolver,并将其赋值给_current_currentCache_currentCache对应的是InnerCurrentCache,该属性在创建View使没有使用,在创建Controller的时候会使用。

     

    然后,调用ViewResult对象View属性的Render方法,次方法首先会创建View实例。

    object instance = null;

     

    Type type = BuildManager.GetCompiledType(ViewPath);

    if (type != null)

    {

    instance = ViewPageActivator.Create(_controllerContext, type);

    }

     

    而实际上,现在的ViewPageActivator实际是newBuildManagerViewEngine.DefaultViewPageActivator(dependencyResolver),而这里的denpendencyResolver就是DefaultDependencyResolver

    OK,我们最后来看一下instance是如何创建的:

    _resolverThunk().GetService(type) ?? Activator.CreateInstance(type);

     

    请注意,_resolverThunk = () => DependencyResolver.Current;由此可见在默认的PageActivator内部的私有Fun变量_resolverThunk同样来自DefaultDependencyResolver.Current

    instance要么DefaultDependencyResolverGetService()创建,要么通过Activator.CreateInstance来创建,其实它们内部根本没有多少差别。

    publicobject GetService(Type serviceType)

    {

    // Since attempting to create an instance of an interface or an abstract type results in an exception, immediately return null

    // to improve performance and the debugging experience with first-chance exceptions enabled.

    if (serviceType.IsInterface || serviceType.IsAbstract)

    {

    returnnull;

    }

     

    try

    {

    returnActivator.CreateInstance(serviceType);

    }

    catch

    {

    returnnull;

    }

    }

     

    由此可见,GetService内部还是调用了Activator.CreateInstance方法创建实例。

     

    剖析如何获取View的具体信息

    1. 获取View的Path

    // show the details of retrieving view path

    publicActionResult List()

    {

    string[] ViewLocationFormats = new[]

    {

    "~/Views/{1}/{0}.cshtml",

    "~/Views/{1}/{0}.vbhtml",

    "~/Views/Shared/{0}.cshtml",

    "~/Views/Shared/{0}.vbhtml"

    };

     

    string name = "List";

    string controllerName = "InnerView";

    string areaName = "";

     

    List<ViewLocation> allLocations = newList<ViewLocation>();

    foreach (string viewLocationFormat in ViewLocationFormats)

    allLocations.Add(newViewLocation(viewLocationFormat));

     

    DisplayModeProvider instance = DisplayModeProvider.Instance;

     

    for (int i = 0; i < allLocations.Count; i++)

    {

    ViewLocation location = allLocations[i];

    string virtualPath = location.Format(name, controllerName, areaName);

    DisplayInfo virtualPathDisplayInfo = instance.GetDisplayInfoForVirtualPath(virtualPath, ControllerContext.HttpContext,

    path => FileExists(ControllerContext, path), null);

    if (virtualPathDisplayInfo == null)

    continue;

    var viewPath = virtualPathDisplayInfo.FilePath;

    Response.Write(viewPath);

    }

     

    return View();

    }

     

    返回结果为:

     

    1. 获取View的对象

    publicActionResult Activator()

    {

     

    // remove the dependency

    IDependencyResolver dependencyResolver = DependencyResolver.Current;

     

    IResolver<IViewPageActivator> activatorResolver = newSingleServiceResolver<IViewPageActivator>(

    () => null, newDefaultViewPageActivator(dependencyResolver), "BuildManagerViewEngine constructor");

     

    IViewPageActivator pageActivator = activatorResolver.Current;

     

    // HelloMVC.Controllers.InnerViewController

    Object controllerInstance = pageActivator.Create(ControllerContext, this.GetType());

     

    // Page instance

    IBuildManager buildManager = newBuildManagerWrapper();

    Object viewpageInstance = pageActivator.Create(ControllerContext, buildManager.GetCompiledType("~/Views/InnerView/List.cshtml "));

     

    Response.Write(string.Format("controllerInstance is {0} <br /> viewpageInstance is {1}", controllerInstance.GetType(), viewpageInstance.GetType()));

    return View();

    }

     

     

     

     

    http://www.professionals-helpdesk.com/2012/08/exploring-mvc-framwwork-in-deep_10.html exploring MVC framework in deep – DependencyResolver Class

     

     

     

     

  • 相关阅读:
    使用 Facebook开源动画库 POP 实现真实衰减动画
    在命名空间下定义类型
    作为程序猿我给csdn博客加入打赏功能
    linux高可用集群heartbeat实现http的高可用
    杭电 HDU 1247 ACMHat’s Words(trie树 或着STL)
    取石子(一)-博弈数论
    区块链技术开发怎么结合已有产业链落地?
    KafkaConsumer assign VS subscribe
    KafkaConsumer assign VS subscribe
    KafkaConsumer assign VS subscribe
  • 原文地址:https://www.cnblogs.com/yang_sy/p/ASPNET_MVC_VIEW_INNER_2.html
Copyright © 2020-2023  润新知