使用Razor View Engine和自定义模板框架

时间:2012-10-30 22:48:11

标签: asp.net asp.net-mvc razor

我们的Web应用程序使用了一个自定义模板框架,其实现是用各种语言编写的,我正在调查是否可以使用Razor View引擎在ASP.NET MVC应用程序中使用它。我们已经有一个使用Web窗体视图引擎的实现,但我也希望能够使用Razor。

模板在html文件中定义,该文件包含在运行时使用适用的html解释和替换的宏标记。以下是此文件的高度简化版本: -

[doctype]
<html>
  <head>
    [HeadScript]
    [HeadSectionText]
  </head>
  <body id="[if Home][Home][else]body[end if]">
    [form]
      [Content]
    [end form] 
    [EndBodyScript]
  </body>
</html>

正如您所看到的,有机会将html注入文档的各个部分,其中一些部分由简单的条件逻辑实现处理。为了在Razor中使用它,我需要能够处理模板中的所有宏标记,包括从正在渲染的Razor视图中插入HTML,并使用此操作的输出作为最终发送的HTML给客户。

在MVC开发方面我很绿,但我知道我可以创建一个自定义的ViewEngine和IView实现。也许我可以使用它来实现我想要的,使用RazorView类的自定义引擎来渲染要插入到我们模板中的实际内容。这听起来像一个可行的解决方案吗?如果是这样,有没有人有任何提示让我开始?

目前我有一个kludgy解决方案,我使用ASP.NET WebForms引擎并渲染部分Razor视图,但长期以来我更愿意有一个解决方案可以完全取消WebForms引擎。

正确方向的任何推动都非常感激。

1 个答案:

答案 0 :(得分:1)

我设法解决了一些问题。虽然我的问题与你的问题不完全一样,但它肯定可以帮到你。但首先要做的事情。

问题

我有很多控件(在我的例子中,它们是部分视图)。例如:

Views/Shared/EditName.cshtml
Views/Shared/EditAddress.cshtml
Views/Shared/EditEmail.cshtml
Views/Shared/EditFavoriteColour.cshtml

我想定义这些控件的组(在数据库或web.config中),例如:

SimpleEditGroup:
    EditName
ExtendedEditGroup:
    EditName
    EditEmail
FullEditGroup:
    EditName
    EditAddress
    EditEmail
    EditFavoriteColour

然后我想基于特定的组渲染视图。我认为以下语法就​​足够了。

@Html.Partial("ControlGroup:ExtendedEditGroup", Model)

解决方案草案

我想创建自己的渲染引擎,它将执行以下操作:

  1. 如果视图的名称以“ControlGroup:”开头,则使用以前定义的组来呈现页面。每个控件都应该由RazorViewEngine呈现。
  2. 如果视图名称不以“ControlGroup:”开头,请让RazorViewEngine完成其工作。
  3. <强>研究

    我找到了以下资源:

    1. 有关CodeProject的文章 - Custom ViewEngine in ASP.NET MVC3
    2. 基于StackOverflow问题的文章 - Creating a Widget system in ASP.NET MVC 3
    3. 我推荐你的书Pro ASP.NET MVC 3 Framework。它将告诉您可以在ASP.NET MVC 3中自定义多少内容
    4. 当然ASP.NET MVC 3 RTM的源代码非常有用。
    5. 最终解决方案

      MyViewEngine:

      public class MyViewEngine : RazorViewEngine
      {
        IDictionary<string, List<string>> groups = new Dictionary<string, List<string>>();
      
        public MyViewEngine()
        {
          // Temporary data source
          groups["SimpleEditGroup"] = new List<string>() { "EditName"};
          groups["ExtendedEditGroup"] = new List<string>() { "EditName", "EditEmail"};
        }
      
        public override ViewEngineResult FindView(ControllerContext controllerContext,
                 string viewName, string masterName, bool useCache)
        {
          if (viewName.StartsWith("ControlGroup"))
          {
            var groupName = viewName.Split(':')[1];
            var controls = new List<ViewEngineResult>();
      
            foreach (var controlName in groups[groupName])
            {
              // Find each control using Razor magic
              var control = base.FindPartialView(controllerContext, controlName, useCache);
              if (control.View != null)
              {
                controls.Add(control);
              }
            }
      
            if(controls.Count > 0)
              return new ViewEngineResult(new MyView(controls), this);
          }
      
          return base.FindView(controllerContext, viewName, masterName, useCache);
        }
      }
      

      MyView.cs:

      public class MyView : IView
      {
        IList<ViewEngineResult> controls;
      
        public MyView(IList<ViewEngineResult> _controls)
        {
          controls = _controls;
        }
      
        public void Render(ViewContext viewContext, TextWriter textWriter)
        {
          // For simplicity I used table for layout
          textWriter.Write("<table border='1'>");
      
          foreach (var ctrl in controls)
          {
            textWriter.Write("<tr><td>");
      
            // Render control using Razor
            ctrl.View.Render(viewContext, textWriter);
      
            textWriter.Write("</td></tr>");
          }
      
          textWriter.Write("</table>");
        }
      }
      

      不要忘记在Global.asax ViewEngines.Engines.Add(new MyViewEngine());

      中注册新引擎

      结局快乐

      我可以通过两种方式使用它:使用Render.Partial嵌入视图或从控制器返回PartialView

      请告诉我它是否对您有所帮助。您也可以分享您的解决方案。