2

我们的 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 类的自定义引擎来呈现要插入到我们模板中的实际内容。这听起来像是一个可行的解决方案吗?如果是这样,有没有人有任何提示让我开始?

目前我有一个笨拙的解决方案,我使用 ASP.NET WebForms 引擎并呈现部分 Razor 视图,但从长远来看,我更希望有一个可以将 WebForms 引擎完全排除在等式之外的解决方案。

非常感谢任何朝着正确方向的推动。

4

1 回答 1

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 完成它的工作。

研究

我找到了以下资源:

  1. CodeProject 上的文章 - ASP.NET MVC3 中的自定义 ViewEngine
  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的源代码非常有帮助。

最终解决方案

我的视图引擎:

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);
  }
}

我的视图.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我的控制器返回嵌入到视图中。

让我知道它是否对您有帮助。您还可以分享您的解决方案。

于 2013-03-07T02:31:54.687 回答