好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

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文件的两个地址。

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

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

作者: Artech
出处: http://artech.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

分类:  [01] 技术剖析

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于ASP.NET MVC的View是如何呈现出来的[实例篇]的详细内容...

  阅读:45次