ASP.NET MVC Preview 2 - NVelocityViewEngine

  在前面做 MVC 流程分析的时候,我曾提到过,我更喜欢用 Velocity 来代替 WebForm。这倒不是说 WebForm 本身有什么不好,更不是某些人所说的 "性能" 原因。在实际开发中,我们所面对的页面往往很复杂,有诸多看上去很头疼的 div、style、span 什么的,我想没有几个 "程序员" 愿意去调整某些个边框布局或者颜色设置。WebForm 基于设计和封装的原因,会使用大量的 "非标准 HTML 代码",这就造成了一个尴尬的局面 —— 美工和页面程序员的矛盾。

  美 工: "你把我设计的页面全搞乱了,你应该用这个样式……"

  程序员: "废话,早跟你说过了。你必须按这样的格式来写……"

  美 工: "我修改了页面,已经发给你了……"

  程序员: "没空,你自己不会改啊?"

  Velocity 是什么,无需我多言。使用一种非常简单的标记或逻辑控制就可以将我们的数据 "嵌入" 到美工设计的页面中。我们可以让美工事先将需要输出数据的位置用 "<!-- 数据1 -->" 之类的东东标注出来,我们也只需关心数据是否正确输出,至于页面的调整和我们基本没有关系。当然,对于有一定兴趣的美工或者组里面的新人,完全可以在一天甚至半天内掌握 Velocity 的使用方法,何乐而不为?要知道,多数网站会频繁调整页面显示,不像我们通常用来演示的那几个 Example 那么简单。

  要使用自定义视图引擎,我们实现需要找到 "注入" 位置。我们在前面的流程分析时,就已经锁定目标 —— ControllerBuilder。

public class GlobalApplication : System.Web.HttpApplication
{
  protected void Application_Start(object sender, EventArgs e)
  {
    ControllerBuilder.Current.SetControllerFactory(new NVelocityContrillerFactory());
  }
}

  NVelocityContrillerFactory 可以直接继承自 DefaultControllerFactory,我们 override 它的方法,将生成的 Controller.ViewEngine 赋值为我们自定义的视图引擎即可。

public class NVelocityContrillerFactory : DefaultControllerFactory
{
  protected override IController GetControllerInstance(Type controllerType)
  {
    var controller = base.GetControllerInstance(controllerType);
    (controller as Controller).ViewEngine = new NVelocityViewEngine();
    return controller;
  }
}

  接下来,我们开始写我们自己的视图引擎。

public class NVelocityViewEngine : IViewEngine
{
  static NVelocityViewEngine()
  {
    Velocity.SetProperty("resource.loader", "file");
    Velocity.SetProperty("file.resource.loader.path", HttpContext.Current.Server.MapPath("~"));
    Velocity.SetProperty("file.resource.loader.cache", true);
    //Velocity.SetProperty("file.resource.loader.modificationCheckInterval", 10L); //seconds
    Velocity.SetProperty("input.encoding", "utf-8");
    Velocity.Init();
  }
  public void RenderView(ViewContext viewContext)
  {
    var locator = new NVelocityViewLocator() as IViewLocator;
    var templatePath = locator.GetViewLocation(viewContext, viewContext.ViewName);
    var template = Velocity.GetTemplate(templatePath);
    var context = new VelocityContext();
    if (viewContext.ViewData != null)
    {
      var properties = viewContext.ViewData.GetProperties(); // 扩展方法,获取全部属性。
      foreach (var item in properties.Keys)
      {
        context.Put(item, properties[item]);
      }
    }
    template.Merge(context, viewContext.HttpContext.Response.Output);
  }
}

也很简单,除了在静态构造里面初始化 NVelocity 以外,我们还对 ViewData 做了些处理。当然,我们最好再来一个 NVelocityViewLocator,以便支持从多个目录中找寻模板文件。

public class NVelocityViewLocator : ViewLocator
{
  public NVelocityViewLocator()
  {
    this.ViewLocationFormats = new[] 
    {
      "/Views/{1}/{0}.vm",
      "/Views/{1}/{0}.htm",
      "/Views/{1}/{0}.html",
      "/Views/Shared/{0}.vm",
      "/Views/Shared/{0}.htm",
      "/Views/Shared/{0}.html",
    };
    this.MasterLocationFormats = new string[0];
  }
}

  我们可以支持更多的扩展名,呵呵~~~~~

  好了,测试一下。

public class HomeController : Controller
{
  public void Index()
  {
    this.RenderView("index", new { Title = "TemplateEngine Test", Name = "Tomcat" });
  }
}

~/View/Home/index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/....dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
 <title>$Title</title>
</head>
<body>
  Hello, $Name!
</body>
</html>

  输出结果

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/....dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
  <title>TemplateEngine Test</title>
</head>
<body>
  Hello, Tomcat!
</body>
</html>

 

  忘了一件重要的事情,NVelocity 可以在 Castle MonoRail 的包里找到。

 

posted @ 2009-10-29 15:56  Silver.Lee  阅读(219)  评论(0编辑  收藏  举报