• 从零开始学习ASP.NET MVC1.O (第五章)


    一.摘要
    本文讲解ViewEngine的作用, 并且深入解析了实现ViewEngine相关的所有接口和类, 最后演示了如何开发一个自定义的ViewEngine. 本系列文章已经全部更新为ASP.NET MVC 1.0版本.希望大家多多支持!
    二.承上启下
    首先注意: 我会将大家在MVC之前一直使用的ASP.NET页面编程模型称作ASP.NET WebForm编程模型.
    上一讲中我们已经学习了如何向View传递Model, 以及如何在View中使用Model对象. 目前为止我们使用的都还是ASP.NET WebForm的页面模型,比如aspx页面,用户控件,母版页等. 最后这些页面中都要转换为HTML代码. 比如页面中的内嵌代码:
    <% = ViewData["model"] %>
    你是否思考过, 为何页面会支持<% %>这种语法? 为何最后一个aspx页面会在浏览器中以HTML代码的形式展现?
    有人会回答这是ASP.NET自带的语法和功能. 没有错, ASP.NET帮我们做了编译页面, 输出HTML, 返回HTML给客户端浏览器等一系列工作.但是这些工作在MVC框架中有很多是属于View角色的职责. 为了继续使用原有的ASP.NET WebForm页面引擎, ASP.NET MVC抽象出来了ViewEngine这个角色. 顾名思义ViewEngine即视图引擎, 其主要作用就是找到View对象, 编译View对象中的语言代码(执行语言逻辑), 并且输出HTML. 下面讲解的WebFormViewEngine就是使用ASP.NET WebForm的页面编译/呈现功能实现的.
    三.ViewEngine解析
    下面将讲解和ViewEngine有关的各个接口和类.
    IView接口
    IView接口是对MVC结构中View对象的抽象, 此接口只有一个方法:
    void Render(ViewContext viewContext, TextWriter writer);
    
    Render方法的作用就是展示View对象, 通常是将页面HTML写入到Writer中供浏览器展示.
    在本系列第三篇文章中我曾经分析过, 虽然IView对象是MVC中View角色的抽象, 并且提供了Render方法, 但是实际上真正的View角色的显示逻辑在ViewPage/ViewUserControl类中. 这是由于ASP.NET MVC提供的WebFormViewEngine视图引擎是使用原有的ASP.NET Web From的页面显示机制, 我们无法直接将WebForm模型中的页面转化为IView对象.
    于是最后使用了一个折中的办法:
    在IView对象的Render方法中调用WebForm页面的Render方法. WebFormView是目前ASP.NET MVC中唯一实现了IView接口的类
    所以如果我们使用自定义的ViewEngine引擎, 就可以直接创建一个实现了IView接口的类实现Render方法.
    
    IViewEngine接口
    ViewEngine即视图引擎, 在ASP.NET MVC中将ViewEngine的作用抽象成了 IViewEngine 接口.
    虽然IViewEngine的职责是寻找View对象, 但是其定义的两个方法:
    • FindPartialView
    • FindView
    返回的结果是ViewEngineResult对象, 并不是View对象. 我们可以将ViewEngineResult理解为一次查询的结果, 在ViewEngineResult对象中包含有本次找到的IView对象.
    ASP.NET MVC 提供了下面两个实现了IViewEngine接口的类:
    • VirtualPathProviderViewEngine
    • WebFormViewEngine
    WebFormViewEngine是VirtualPathProviderViewEngine的派生类.
    VirtualPathProviderViewEngine类实现了FindPartialView/FindView方法, 更够根据指定的路径格式搜索页面文件, 并且使用了提供了Cache机制缓存数据. 注意因为使用的是ASP.NET Cache,依赖HttpContext对象, 这就导致Cache无法在WebService或者WCf等项目中使用. VirtualPathProviderViewEngine寻找页面的方法依赖下面三个属性:
    • MasterLocationFormats
    • ViewLocationFormats
    • PartialViewLocationFormats
    在VirtualPathProviderViewEngine中只定义了这三个属性, 具体的值在派生类WebFormViewEngine中指定:
     public WebFormViewEngine() {
     MasterLocationFormats = new[] {
     "~/Views/{1}/{0}.master",
     "~/Views/Shared/{0}.master"
     };
    
     ViewLocationFormats = new[] {
     "~/Views/{1}/{0}.aspx",
     "~/Views/{1}/{0}.ascx",
     "~/Views/Shared/{0}.aspx",
     "~/Views/Shared/{0}.ascx"
     };
    
     PartialViewLocationFormats = ViewLocationFormats;
     }
    上面的代码中我们可以一步了然ViewEngine都搜索哪些路径.甚至还可以添加我们自己的路径和文件类型.
    因为有了VirtualPathProviderViewEngine类, 在开发自定义的ViewEngine时不需要再编写搜索View文件的逻辑了.只需要定义搜索路径即可. 如果不使用ASP.NET WebForm的页面显示方式, 就需要自己定义的View对象如何显最后转化为HTML代码.
    在后面的实例中会演示创建一个我们自定义的ViewEngine.
    
    ViewEngineResult
    ViewEngineResult是ViewEngine寻找View的查询结果.ViewEngineResult类没有派生类, 也就是说不同的ViewEngine返回的结果都是ViewEngineResult对象.
    ViewEngineResult类有一个很重要的构造函数:
    public ViewEngineResult(IView view, IViewEngine viewEngine)
    
    以WebFormViewEngine为例, 在WebFormViewEngine类中定义了 MasterLocationFormats/ViewLocationFormats /PartialViewLocationFormats , 在调用FindPartialView/FindView方法时, 首先找到View对象的磁盘路径, 然后使用CreatePartialView/CreateView方法将磁盘路径转化实现了IView接口的WebFormView对象.
    WebFormView中依然保存这页面对象的磁盘路径, 在调用Render时会根据磁盘路径创建ViewPage对象, 调用页面的Render方法.ASP.NET MVC编译页面时, 使用了.NET Framework 2.0以上的版本中提供的根据虚拟路径编译页面的函数:
    BuildManager.CreateInstanceFromVirtualPath(string virtualPath, Type requiredBaseType)
    命名空间为System.Web.Compilation.
    
    ViewEngineCollection
    ViewEngineCollection是IViewEngine对象的集合类. 在我们的系统中可以使用多个ViewEngine, 在寻找时会返回第一个匹配的ViewEngineResult, 下面是ViewEngineCollection类的Find方法代码:
     private ViewEngineResult Find(Func cacheLocator, Func locator) {
     ViewEngineResult result;
    
     foreach (IViewEngine engine in Items) {
     if (engine != null) {
     result = cacheLocator(engine);
    
     if (result.View != null) {
     return result;
     }
     }
     }
    
     List searched = new List();
    
     foreach (IViewEngine engine in Items) {
     if (engine != null) {
     result = locator(engine);
    
     if (result.View != null) {
     return result;
     }
    
     searched.AddRange(result.SearchedLocations);
     }
     }
    
     return new ViewEngineResult(searched);
     }
  • 相关阅读:
    TortoiseGit 文件比对工具使用 Beyond Compare 和 DiffMerge
    IE8/9 本地预览上传图片
    IT人经济思维之投资
    4、界面前端设计师指南
    IT软件人员的技术学习内容(写给技术迷茫中的你)
    IT从业者的职业道路(从程序员到部门经理)
    jQuery插件库代码分享
    Magical平台类库代码分享
    软件外包的启示
    2、员工的激励与自我激励
  • 原文地址:https://www.cnblogs.com/cxd4321/p/1575436.html
Copyright © 2020-2023  润新知