使用带有自定义模板框架的Razor视图引擎。

时间:2021-12-15 23:16:00

We have a custom templating framework used by our web applications with implementations which are written in a variety of languages, and I'm investigating whether its possible to use this in an ASP.NET MVC application using the Razor View engine. We already have an implementation that uses the Web Forms View engine, but I'm keen to be able to use Razor as well.

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

The template is defined in a html file which contains macro tags that are interpreted and replaced at runtime with the applicable html. Below is a highly simplified version of this file:-

模板在包含宏标记的html文件中定义,这些宏标记在运行时被解释为适用的html。下面是这个文件的高度简化版本:-

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

As you can see, there are opportunities to inject html into various sections of the document, with some of this being handled by a simple conditional logic implementation. In order to use this with Razor, I'd need to be able to process all the macro tags in the template, including inserting the HTML from the Razor view being rendered, and use the output of this operation as the HTML to be ultimately sent to the client.

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

I'm pretty green when it comes to MVC development, but I know I can create a custom ViewEngine and IView implementation. Perhaps I can use this to achieve what I want, with a custom engine using the RazorView class to render the actual content to be inserted into our template. Does this sound like a feasible solution? And if so, does anyone have any tips to get me started?

说到MVC开发,我还是个新手,但是我知道我可以创建一个自定义的ViewEngine和IView实现。也许我可以使用这个来实现我想要的,使用自定义引擎使用RazorView类来呈现要插入到模板中的实际内容。这听起来是一个可行的解决方案吗?如果是这样的话,有人有什么建议可以让我开始吗?

Currently I have a kludgy solution where I use the ASP.NET WebForms engine and render partial Razor views, but longterm I'd prefer to have a solution that can take the WebForms engine out of the equation entirely.

目前,我有一个使用ASP的拼凑型解决方案。NET WebForms引擎和呈现局部剃刀视图,但长期来看,我希望有一个解决方案,可以将WebForms引擎完全排除在等式之外。

Any shoves in the right direction greatly appreciated.

任何朝着正确的方向努力的人都非常感激。

1 个解决方案

#1


1  

I've managed to figure something out. Although my problem is not exactly the same you have, but it can certainly help you. But first things first.

我想了个办法。虽然我的问题和你的不完全一样,但它肯定能帮助你。但先做重要的事。

The problem

这个问题

I have a number of controls (in my case they are Partial Views). For example:

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

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

I want to define groups of these controls (in database or web.config), for example:

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

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

Then I want to render a view based on a particular group. I was thinking the following syntax would be sufficient.

然后我想基于一个特定的组呈现一个视图。我想下面的语法就足够了。

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

Draft of the solution

解决方案的草案

I wanted to create my own render engine which will do the following:

我想创建我自己的渲染引擎,它会做如下工作:

  1. If the name of the view begins with "ControlGroup:" then use previously defined groups to render the page. Each of the controls should be rendered by RazorViewEngine.
  2. 如果视图的名称以“ControlGroup:”开头,则使用先前定义的组来呈现页面。每个控件都应该由RazorViewEngine呈现。
  3. If the name of the view doesn't begin with "ControlGroup:" just let the RazorViewEngine do its work.
  4. 如果视图的名称不以“ControlGroup:”开头,那么就让RazorViewEngine完成它的工作。

Research

研究

I've found following resources:

我发现以下资源:

  1. Article on CodeProject - Custom ViewEngine in ASP.NET MVC3
  2. 关于代码项目的文章——ASP中的自定义视图引擎。净MVC3
  3. Article based on * question - Creating a Widget system in ASP.NET MVC 3
  4. 文章基于*问题——在ASP中创建一个小部件系统。净MVC 3
  5. I recommend you the book Pro ASP.NET MVC 3 Framework. It will give you the idea how many things you can customize in ASP.NET MVC 3
  6. 我向你推荐这本书。净MVC 3框架。它将使您了解可以在ASP中定制多少东西。净MVC 3
  7. Of course source code of ASP.NET MVC 3 RTM was very helpful.
  8. 当然是ASP的源代码。NET MVC 3 RTM非常有用。

Final solution

最终的解决方案

MyViewEngine:

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:

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

Don't forget to register your new engine in Global.asax ViewEngines.Engines.Add(new MyViewEngine());

不要忘记在全球注册你的新引擎。asax ViewEngines.Engines。添加(新MyViewEngine());

Happy ending

快乐的结局

I can use this in two ways: embedded in a view using Render.Partial or just returning PartialView from my controller.

我可以用两种方式使用:使用渲染嵌入视图。从我的控制器返回部分视图。

Let me know if it helps you. And also you can share your solution.

如果对你有帮助,请告诉我。你也可以分享你的解决方案。

#1


1  

I've managed to figure something out. Although my problem is not exactly the same you have, but it can certainly help you. But first things first.

我想了个办法。虽然我的问题和你的不完全一样,但它肯定能帮助你。但先做重要的事。

The problem

这个问题

I have a number of controls (in my case they are Partial Views). For example:

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

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

I want to define groups of these controls (in database or web.config), for example:

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

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

Then I want to render a view based on a particular group. I was thinking the following syntax would be sufficient.

然后我想基于一个特定的组呈现一个视图。我想下面的语法就足够了。

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

Draft of the solution

解决方案的草案

I wanted to create my own render engine which will do the following:

我想创建我自己的渲染引擎,它会做如下工作:

  1. If the name of the view begins with "ControlGroup:" then use previously defined groups to render the page. Each of the controls should be rendered by RazorViewEngine.
  2. 如果视图的名称以“ControlGroup:”开头,则使用先前定义的组来呈现页面。每个控件都应该由RazorViewEngine呈现。
  3. If the name of the view doesn't begin with "ControlGroup:" just let the RazorViewEngine do its work.
  4. 如果视图的名称不以“ControlGroup:”开头,那么就让RazorViewEngine完成它的工作。

Research

研究

I've found following resources:

我发现以下资源:

  1. Article on CodeProject - Custom ViewEngine in ASP.NET MVC3
  2. 关于代码项目的文章——ASP中的自定义视图引擎。净MVC3
  3. Article based on * question - Creating a Widget system in ASP.NET MVC 3
  4. 文章基于*问题——在ASP中创建一个小部件系统。净MVC 3
  5. I recommend you the book Pro ASP.NET MVC 3 Framework. It will give you the idea how many things you can customize in ASP.NET MVC 3
  6. 我向你推荐这本书。净MVC 3框架。它将使您了解可以在ASP中定制多少东西。净MVC 3
  7. Of course source code of ASP.NET MVC 3 RTM was very helpful.
  8. 当然是ASP的源代码。NET MVC 3 RTM非常有用。

Final solution

最终的解决方案

MyViewEngine:

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:

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

Don't forget to register your new engine in Global.asax ViewEngines.Engines.Add(new MyViewEngine());

不要忘记在全球注册你的新引擎。asax ViewEngines.Engines。添加(新MyViewEngine());

Happy ending

快乐的结局

I can use this in two ways: embedded in a view using Render.Partial or just returning PartialView from my controller.

我可以用两种方式使用:使用渲染嵌入视图。从我的控制器返回部分视图。

Let me know if it helps you. And also you can share your solution.

如果对你有帮助,请告诉我。你也可以分享你的解决方案。