体验AspNet MVC Preview5(2)-实战自定义View及多ViewEngine协作


文中的测试工程下载:http://file.ddvip.com/2008_10/1225160208_ddvip_3908.rar

  在上篇中,我们分别了解了两个系统对ViewEngine的处理,那么接下来我们来实战一下,使用asp.net mvc p5来添加自己的ViewEngine并同时使用多个ViewEngine来呈现数据.

  在这个例子中,工程和文件结构如下图:

  

  在Library的程序集中,我们新增两个ViewEngine,分表是LViewEngine和WebViewEngine,并新增LView来具体呈现数据,供LViewEngine使用,而WebViewEngine使用系统自带的WebFormView来呈现数据.EngineManager用来管理ViewEngine.以实现系统换肤.BaseController继承自Controller,为web系统中所有Contoller的基类.

  首先看LViewEngine类,该类代码如下:

public class LViewEngine : VirtualPathProviderViewEngine
  {
    public LViewEngine(string path)
    {
      base.MasterLocationFormats = new string[] {};
      base.ViewLocationFormats = new string[] { "~/skins/" + path + "/{1}/{0}.txt", "~/skins/" + path + "/shared/{0}.txt" };
      base. PartialViewLocationFormats = base.ViewLocationFormats;
    }
    public LViewEngine()
      : this("default")
    {
    }
    protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
    {
      return new LView(partialPath);
    }
    protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
    {
      return new LView(viewPath);
    }
}

它继承自系统的VirtualPathProviderViewEngine,由于VirtualPathProviderViewEngine中封装好了对View路径的处理,因此继承自它可以让我们免于对路径的处理.在构造方法中.我们对MasterLocationFormats, ViewLocationFormats, PartialViewLocationFormats进行了设定,它们分表表示Master的路径选择,View的路径选择和PartialView的路径选择.当更改path的时候系统会将选择view的目录进行更改,从而实现了换肤. CreatePartialView和CreateView分别用于返回该ViewEngine对应的View.在这儿,我们返回的是LView.

  然后我们再看LView部分,代码如下:

  Code

public class LView : IView
  {
    public string ViewPath { get; private set; }
    public LView(string viewPath)
    {
      if (string.IsNullOrEmpty(viewPath))
      {
        throw new ArgumentException("view路径不能为空.", "viewPath");
      }
      ViewPath = viewPath;
    }
    public void Render(ViewContext viewContext, TextWriter writer)
    {
      StringBuilder sb = new StringBuilder(GetViewString(viewContext.HttpContext.Server));
      foreach (var item in viewContext.ViewData)
      {
        sb.Replace("{$" + item.Key + "}", item.Value.ToString());
      }
      if (viewContext.ViewData.Model != null)
      {
        Type mType = viewContext.ViewData.Model.GetType();
        System.Reflection.PropertyInfo[] pis = mType.GetProperties();
        if (pis.Length > 0)
        {
          foreach (System.Reflection.PropertyInfo pi in pis)
          {
            sb.Replace("{$." + pi.Name + "}", pi.GetValue(viewContext.ViewData.Model, null).ToString());
          }
        }
      }
      writer.Write(sb.ToString());
    }
    private string GetViewString(HttpServerUtilityBase server)
    {
      using (FileStream fs = new FileStream(server.MapPath(ViewPath), FileMode.Open, FileAccess.Read, FileShare.Read))
      {
        StreamReader sr = new StreamReader(fs, Encoding.UTF8);
        return sr.ReadToEnd();
      }
    }

这是一个非常简单的自定义View实现,它的功能是读取指定路径的txt文件,然后对其中的{$}标记进行替换,替换规则为,对ViewData中的数据根据Key和Value进行替换,比如{$test}将被替换为ViewData[“test”],对Model的数据进行属性替换,如,{$.test}将被替换为ViewData.Model.test.至于实现方法,不再细谈.

  再看WebViewEngine,它相当是对系统自带的一个WebFormView的封装.本来WebFormViewEngine是查找Views下的文件.我们进行修改后也将支持换肤功能,根据不同的path参数来使用不同的view文件(在老版本中,要实现该功能必须定义自己的ViewLocater类,然后继承Controller,在Controller中替换本身的ViewLocater).

  而在EngineManager中,提供了ChangeSkin方法,它可以方便的将系统的view路径更改.

  下面我们来测试我们自带的LView,在web项目中,新建Global.asax,修改关键代码:

  Code

protected void Application_Start(object sender, EventArgs e)
    {
      InitRouting(RouteTable.Routes);
      InitDefaultViewEngine();
    }
    private static void InitRouting(RouteCollection routes)
    {
      routes.MapRoute("default",
        "{controller}/{action}",
        new { controller = "article", action = "index" });
    }
    private static void InitDefaultViewEngine()
    {
      EngineManager.LoadDefaultSkin();
    }

  分别用来初始化Routing和设置初始skin.

然后新建ArticleController,加入一个index方法,代码如下:

  Code

[ActionName("index"), AcceptVerbs("GET")]
    public ActionResult Index()
    {
      ViewData["title"] = "LView Test";
      ViewData.Model = new { info = "Hello,World." };
      return View();
    }

  然后新增skins/default/article/index.txt文件.文件内容如下:

  Code

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
  <title>{$title}</title>
</head>
<body>
  <div>
  {$.info}
  </div>
</body>
</html>

  测试实例图:

  

  很好,LView已经工作正常了.

  然后我们测试多个View的混合工作.

  添加新的方法:

[ActionName("mixer"), AcceptVerbs("GET")]
    public ActionResult Mixer()
    {
      return View();
    }

  然后添加skins/default/article/mixer.aspx文件.代码如下

Code

<%@ Page Language="C#" AutoEventWireup="true" Inherits="System.Web.Mvc.ViewPage, System.Web.Mvc" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
  <title>多引擎测试页面</title>
</head>
<body>
  <div>
  <%Html.RenderPartial("top", new
   {
     title = "this part render by mixer.aspx",
     introduction = "use defferent view engine in one page.",
     content = "in asp.net mvc p5, you can use more then one view engine in one page."
   }); %>
  </div>
  <%Html.RenderPartial("foot", new { info = "copyright 2008 &copy; example." }); %>
</body>
</html>

  这儿有两个Html.RenderPartial调用,分表呈现top和foot.从工程中可以看到.我们拥有skins/default/article/top.txt和skins/default/article/foot.ascx文件.按照我们的设想,在呈现top会使用LView,在呈现foot的时候会使用WebFormView.

  Top.txt的代码如下:

  Code

<h2>{$.title}</h2>
<span>{$.introduction}</span>
<br />
<span style="font-size:25px;">{$.content}</span>

  Foot.ascx代码如下:

  Code

<%@ Control Language="C#" AutoEventWireup="true" Inherits="System.Web.Mvc.ViewUserControl, System.Web.Mvc" %>
<%
  Type mType = ViewData.Model.GetType();
%>
<%=mType.GetProperty("info").GetValue(ViewData.Model, null) %>

  最后查看效果:

  

  恭喜.多个viewengine都工作的很好.

  到这儿,本篇文章的任务已经全部完成

本文作者:
« 
» 
快速导航

Copyright © 2016 phpStudy | 豫ICP备2021030365号-3