zoukankan      html  css  js  c++  java
  • ASP.NET MVC的View是如何呈现出来的[实例篇]

    在《[设计篇]》篇中我们通过对View引擎的总体介绍讲述了从ViewResult的创建到View呈现的原理,为了让读者对View引擎及其View呈现机制具有一个深刻的认识,我们自定义一个简单的用于呈现静态HTML的StaticFileViewEngine。在一个通过Visual Studio的ASP.NET MVC项目模板创建的空Web应用中,我们定义了如下一个针对于静态HTML内容呈现的自定义StaticFileView。StaticFileView实现了IView接口,在实现的Render方法中读取制定文件的内容写入作为参数的TextWriter。 [本文已经同步到《How ASP.NET MVC Works?》中]

       1: public class StaticFileView:IView
       2: {
       3:     public string FileName { get; private set; }
       4:     public StaticFileView(string fileName)
       5:     {
       6:         this.FileName = fileName;
       7:     }
       8:     public void Render(ViewContext viewContext, TextWriter writer)
       9:     {
      10:         byte[] buffer;
      11:         using (FileStream fs = new FileStream(this.FileName, FileMode.Open))
      12:         { 
      13:             buffer = new byte[fs.Length];
      14:             fs.Read(buffer, 0, buffer.Length);
      15:         }
      16:         writer.Write(Encoding.UTF8.GetString(buffer));
      17:     }
      18: }

    由于StaticFileView中定义的内容完全是静态的,所以缓存显得很有必要。我们只需要基于Controller和View名称对View实施缓存,为此我们定义了如下一个作为Key的数据类型ViewEngineResultCacheKey。

       1: internal class ViewEngineResultCacheKey
       2: {
       3:     public string ControllerName { get; private set; }
       4:     public string ViewName { get; private set; }
       5:  
       6:     public ViewEngineResultCacheKey(string controllerName, string viewName)
       7:     {
       8:         this.ControllerName = controllerName ?? string.Empty;
       9:         this.ViewName = viewName ?? string.Empty;
      10:     }
      11:     public override int GetHashCode()
      12:     {
      13:         return this.ControllerName.ToLower().GetHashCode() ^ this.ViewName.ToLower().GetHashCode();
      14:     }
      15:  
      16:     public override bool Equals(object obj)
      17:     {
      18:         ViewEngineResultCacheKey key = obj as ViewEngineResultCacheKey;
      19:         if (null == key)
      20:         {
      21:             return false;
      22:         }
      23:         return key.GetHashCode() == this.GetHashCode();
      24:     }
      25: }

    具有如下定义的StaticFileViewEngine代表StaticFileView对应的ViewEngine。我们通过一个字典类型的字段viewEngineResults作为对ViewEngineResult的缓存,而View的获取操作最终实现在InternalFindView方法中。通过StaticFileView表示的View定义在一个以View名称作为文件名的文本文件中,该文件的扩展名为.shtml(Static HTML)。

       1: public class StaticFileViewEngine : IViewEngine
       2: {
       3:     private Dictionary<ViewEngineResultCacheKey, ViewEngineResult> viewEngineResults = new Dictionary<ViewEngineResultCacheKey, ViewEngineResult>();
       4:     private object syncHelper = new object();
       5:     public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
       6:     {
       7:         return this.FindView(controllerContext, partialViewName, null, useCache);
       8:     }
       9:  
      10:     public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
      11:     {
      12:         string controllerName = controllerContext.RouteData.GetRequiredString("controller");
      13:         ViewEngineResultCacheKey key = new ViewEngineResultCacheKey(controllerName, viewName);
      14:         ViewEngineResult result;
      15:         if (!useCache)
      16:         { 
      17:             result = InternalFindView(controllerContext, viewName, controllerName);
      18:             viewEngineResults[key] = result;
      19:             return result;
      20:         }
      21:         if(viewEngineResults.TryGetValue(key, out result))
      22:         {
      23:             return result;
      24:         }
      25:         lock (syncHelper)
      26:         {
      27:             if (viewEngineResults.TryGetValue(key, out result))
      28:             {
      29:                 return result;
      30:             }
      31:  
      32:             result = InternalFindView(controllerContext, viewName, controllerName);
      33:             viewEngineResults[key] = result;
      34:             return result;
      35:         }             
      36:     }
      37:  
      38:     private ViewEngineResult InternalFindView(ControllerContext controllerContext, string viewName, string controllerName)
      39:     {
      40:         string[] searchLocations = new string[]
      41:         {
      42:             string.Format( "~/views/{0}/{1}.shtml", controllerName, viewName),
      43:             string.Format( "~/views/Shared/{0}.shtml", viewName)
      44:         };
      45:  
      46:         string fileName = controllerContext.HttpContext.Request.MapPath(searchLocations[0]);
      47:         if (File.Exists(fileName))
      48:         {
      49:             return new ViewEngineResult(new StaticFileView(fileName), this);
      50:         }
      51:         fileName = string.Format(@"\views\Shared\{0}.shtml", viewName);
      52:         if (File.Exists(fileName))
      53:         {
      54:             return new ViewEngineResult(new StaticFileView(fileName), this);
      55:         }
      56:         return new ViewEngineResult(searchLocations);
      57:     }
      58:  
      59:     public void ReleaseView(ControllerContext controllerContext, IView view)
      60:     { }
      61: }

    在InternalFindView中,我们先在“~/Views/{ControllerName}/”目录下寻找View文件,如果不存在则在“~/Views/Shared/”寻找。如果对应View文件被找到,则以此创建一个StaticFileView对象,并最终返回封装该View对象的ViewEngineResult。如果目标View文件找不到,则根据基于这两个目录的搜寻地址列表创建并返回对应的ViewEngineResult。 现在我们在Global.asax通过如下的代码对自定义的StaticFileViewEngine进行注册,我们将创建的StaticFileViewEngine作为第一个使用的ViewEngine。

       1: public class MvcApplication : System.Web.HttpApplication
       2: {
       3:     protected void Application_Start()
       4:     {
       5:         //其他操作
       6:         ViewEngines.Engines.Insert(0, new StaticFileViewEngine());
       7:     }
       8: }

    然后我们定义了如下一个简单的HomeController,Action方法ShowNonExistentView中通过调用View方法呈现一个不存在的View(NonExistentView),而ShowStaticFileView方法则将对应的StaticFileView呈现出来。

       1: public class HomeController : Controller
       2: {
       3:     public ActionResult ShowNonExistentView()
       4:     {
       5:         return View("NonExistentView");
       6:     }
       7:  
       8:     public ActionResult ShowStaticFileView()
       9:     {
      10:         return View();
      11:     }
      12: }

    我们为Action方法ShowStaticFileView创建一个StaticFileView类型的View文件ShowStaticFileView.shtml(该View文件保存在“~/Views/Home”目录下,扩展名不是.cshtml,而是shtml),其内容就是如下一段完整的HTML。

       1: <!DOCTYPE html>
       2: <html>
       3:     <head>
       4:         <title>Static File View</title>
       5:     </head>
       6:     <body>
       7:         这是一个自定义的StaticFileView!
       8:     </body>
       9: </html>

    现在运行我们的程序,在浏览器中输入相应的地址访问Action方法ShowNonExistentView,会得到如下图所示的输出结果。图中列出的View搜寻位置列表中的前两项正是我们自定义的StaticFileViewEngine寻找对应.shtml文件的两个地址。

    image

    如果我们改变浏览器的地址来访问另一个Action方法ShowStaticFileView,会呈现出如下图所示的输出结果,不难看出呈现出来的正是定义在ShowStaticFileView.shtml中的HTML。

    image

    ASP.NET MVC的View是如何被呈现出来的?[设计篇] 
    ASP.NET MVC的View是如何被呈现出来的?[实例篇]

    作者:Artech
    出处:http://artech.cnblogs.com/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    【NOIP 2003】 加分二叉树
    【POJ 1655】 Balancing Act
    【HDU 3613】Best Reward
    【POJ 3461】 Oulipo
    【POJ 2752】 Seek the Name, Seek the Fame
    【POJ 1961】 Period
    【POJ 2406】 Power Strings
    BZOJ3028 食物(生成函数)
    BZOJ5372 PKUSC2018神仙的游戏(NTT)
    BZOJ4836 二元运算(分治FFT)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2652021.html
Copyright © 2011-2022 走看看