一、简介

  在MVC以外的场景中,我们往往需要完成一些模板引擎生成代码或页面的工作;在以前我们一般常用的有Razor、NVeocity、VTemplate。虽然所有的模板系统都具有一些共同特征,但 Razor却和我们前面讨论的二种视图引擎截然不同。不同于其它视图引擎,Razor在使用XML代 码方面没有走得那么极端。它也不完全类似于ASPX,因为它把那些比较笨重的占位符替换成@符号接表达式或者普通的控制块。因为不需要特殊的结束标记,所 以Razor最终的代码很简练。

  本篇介绍的主角是Razor,在非Core的版本中,我们常用开源的RazorEngine来解决我们的问题;但是它却没有对应.NET Core的版本。我们也只要自己动手来完成一个支持.NET Core的“模板引擎”版本。

  一般情况下使用Razor作为视图引擎要实现如下步骤:

  (1)读取模板文件 -> (2)生成Raozr的C#代码 -> (3)使用Roslyn编译代码生成程序集 -> (4)动态加载程序集 -> (5)反射调用

  

二、非Mvc中使用Razor

  我们一般在使用Razor时都是在ASP.NET MVC中使用.cshtml来作为模板,由ASP.NET MVC的视图引擎(ViewEngine)来生成页面的代码的,总之,这里想说的是,模板引擎是独立的,它们甚至是独立的项目,由不同的公司和组织来开发。这次我们要在非Mvc中使用Raozr;首先我们要“脱离”Mvc的环境。

这里我们只在.NET Core程序中引用微软Raozr部分的程序集Microsoft.AspNetCore.Razor 1.0版本,这个程序集负责将模板生成出C#代码。

1.Project.json添加引用

 "dependencies": {
"Microsoft.AspNetCore.Razor": "1.0.0"
"NETStandard.Library": "1.6.0"
}

2.模板生成代码

  如下是摘录的YOYOFx框架中的一段代码,因为我们要生成代码时一般需要传入Model数据,这时需要Model Type组织代码时,要将泛型的情况考虑进去 。这里的RazorViewTemplate是一个模板基类,这里包含了模板中调用的外部方法,我们常用到的如HtmlHelper、Render、Url、Raw等方法或类都是通过这个柜顶模板定义的,RazorViewTemplate是一个自定义类不需要继承其它类型,如果想扩展模板中使用的方法,只需要在这个类中加入即可。

    public class CodeGenerateService
{
public GeneratorResults Generate(Type modelType,string template)
{
//准备临时类名,读取模板文件和Razor代码生成器
string templateType = "YOYO.AspNetCore.ViewEngine.Razor.RazorViewTemplate";
string templateTypeName = modelType != null ? string.Format(templateType + @"<{0}>", modelType.FullName) : templateType;
var class_name = "c" + Guid.NewGuid().ToString("N");
var host = new RazorEngineHost(new CSharpRazorCodeLanguage(), () => new HtmlMarkupParser())
{
DefaultBaseClass = templateTypeName,
DefaultClassName = class_name,
DefaultNamespace = "YOYO.AspNetCore.ViewEngine.Razor",
GeneratedClassContext =
new GeneratedClassContext("Execute", "Write", "WriteLiteral", "WriteTo",
"WriteLiteralTo",
"RazorViewTemplate.Dynamic", new GeneratedTagHelperContext())
};
host.NamespaceImports.Add("System");
host.NamespaceImports.Add("System.Dynamic");
host.NamespaceImports.Add("System.Linq");
host.NamespaceImports.Add("System.Collections.Generic");
var engine = new RazorTemplateEngine(host);
return engine.GenerateCode(new StringReader(template));
}
}

  通过以上代码得到GeneratorResults类型的结果,从而可以得知生成过程是否成功,错误在位置等信息。最后通过GeneratedCode属性,得到生成好的C#代码。

3.编译模板

  一般Razor的C#代码生成后,都是通过CodeDom来生成和编译代码的;.NET开源后,我们又多了一个强大的选择Roslyn , Roslyn也是支持.NET Core的,并且在整个.NET平台中,扮演着非常重要的角色,小到这种视图代码编译,大到整个项目的编译场景都有Roslyn的身影。微软最新开源的Visual Studio Code中C#插件,OmniSharp就是通过Roslyn来对项目和编辑器提供支持的。

  摘录YOYOFx代码如下:

public Type Compile(string compilationContent)
{
var assemblyName = Path.GetRandomFileName();
var sourceText = SourceText.From(compilationContent, Encoding.UTF8);
var syntaxTree = CSharpSyntaxTree.ParseText( sourceText, path: assemblyName, options: new CSharpParseOptions());
var compilation = CSharpCompilation.Create(assemblyName, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary),
    syntaxTrees: new[] { syntaxTree },
    references: ApplicationReferences );
using (var assemblyStream = new MemoryStream())
   {
var result = compilation.Emit(assemblyStream, options: new EmitOptions(debugInformationFormat: DebugInformationFormat.PortablePdb));
this.CompileResult = new CompileResult(){ Success = result.Success, Errors = result.Diagnostics.Select(d => d.ToString()).ToList()};
if (!result.Success){
if (!compilation.References.Any() && !ApplicationReferences.Any())
throw new InvalidOperationException("project.json preserveCompilationContext");
return null;
}
var templateType = LoadTypeForAssemblyStream(assemblyStream, null);
return templateType;
}
}

  在代码中可以通过CompileResult得到相应的编译错误信息,同样包括错误的信息和具体错误所在的行。

  其中注意的是LoadTypeForAssemblyStream方法,因为在.NET Core中动态加载程序集的方式跟以前有所不同AppDomain的概念现在已经消失,所以要在.NET Core动态加载程序集要使用,命名空间System.Runtime.Loader中的AssemblyLoadContext.Default.LoadFromStream 方法,而在.NET 4.5+中要使用Assembly.Load方法。

三、总结

   Razor 不仅仅使用了动态的编译,还有一个强大的模板解析的功能。利用自定义的模板基类还可以在模板里提供一些辅助方法。这样看来 Razor 也算是 C# DSL 的一种实现了。

  GitHubhttps://github.com/maxzhang1985/YOYOFx  如果觉还可以请Star下, 欢迎一起交流。

  .NET Core 和 YOYOFx 的交流群: 214741894

  如果你觉得本文对你有帮助,请点击“推荐”,谢谢.

.NET Core中使用Razor模板引擎的更多相关文章

  1. Core中使用Razor视图引擎渲染视图为字符串 阅读目录

    Core中使用Razor视图引擎渲染视图为字符串 } <!DOCTYPE html> <html> <head> <title>Render view ...

  2. ASP.NET Core中使用Razor视图引擎渲染视图为字符串

    一.前言 在有些项目需求上或许需要根据模板生产静态页面,那么你一样可以用Razor语法去直接解析你的页面从而把解析的页面生成静态页,这样的使用场景很多,不限于生成静态页面,视图引擎为我们提供了模型到视 ...

  3. ASP.NET Core中使用Razor视图引擎渲染视图为字符串(转)

    一.视图渲染说明 在有些项目需求上或许需要根据模板生产静态页面,那么你一样可以用Razor语法去直接解析你的页面从而把解析的页面生成静态页,这样的使用场景很多,不限于生成静态页面,视图引擎为我们提供了 ...

  4. WebApi中利用Razor模板引擎来生成html

    在服务器端基于Razor来生成html的一个思路 using System.Web.Mvc; using System.IO; using System.Web.Routing; using Syst ...

  5. MVC的验证(模型注解和非侵入式脚本的结合使用) .Net中初探Redis .net通过代码发送邮件 Log4net (Log for .net) 使用GDI技术创建ASP.NET验证码 Razor模板引擎 (RazorEngine) .Net程序员应该掌握的正则表达式

    MVC的验证(模型注解和非侵入式脚本的结合使用)   @HtmlHrlper方式创建的标签,会自动生成一些属性,其中一些属性就是关于验证 如图示例: 模型注解 通过模型注解后,MVC的验证,包括前台客 ...

  6. Razor模板引擎

    Razor模板引擎 阅读目录 一.简介 二.非Mvc中使用Razor 三.总结 回到目录 一.简介 在MVC以外的场景中,我们往往需要完成一些模板引擎生成代码或页面的工作:在以前我们一般常用的有Raz ...

  7. 【翻译】介绍 ASP.NET Core 中的 Razor Pages

    介绍 ASP.NET Core 中的 Razor Pages 原文地址:Introduction to Razor Pages in ASP.NET Core         译文地址:介绍 asp. ...

  8. Asp.net MVC Razor模板引擎技巧分享

    Razor是Asp.net MVC中新的默认模板类型, 语法简单易用.这篇文章不涉及Razor的语法,主要介绍Razor的一些在MVC项目中的使用技巧,以及脱离MVC环境下,如何使用Razor. 阅读 ...

  9. MVC Razor模板引擎输出HTML或者生产HTML文件

    以前做CMS的时候都会根据模板来生成输出HTML或者生成HTML文件. 常用的引擎有VTemplate.NVelocity等等,这个我就布做介绍了. 这里我想说的是.当mvc出现Razor模板引擎的时 ...

随机推荐

  1. 生产环境下实践DDD中的规约模式

    最近的开发工作涉及到两个模块“任务”和“日周报”.关系是日周报消费任务,因为用户在写日周报的时候,需要按一定的规则筛选当前用户的任务,作为日周报的一部分提交.整个项目采用类似于Orchard那种平台加 ...

  2. 图解js中常用的判断浏览器窗体、用户屏幕可视区域大小位置的方法

    有时我们需要获得浏览器窗口或屏幕的大小.窗口下拉框下拉的距离等数据,对应这些需求,js中提供了不少解决方法,只是数量稍多容易混淆它们各自的意义,下面咱们用图例来解释下12个常见对象属性的作用. 其中有 ...

  3. Windows Phone App的dump文件实例分析-Stack Overflow

    前言 这篇文章我们一起来分析一个从Windows Phone Dev Center上下载下来的dump file.首先按照我上一篇的步骤设置好我们的Windbg,并按住Ctrl +D打开dumpfil ...

  4. chrome的自动缓存真是讨厌。

    最近老是遇到这样一个问题,为什么我的代码改了,页面却一点变化都没有,难道代码错了,打开chrome的调试窗口一看,md,页面根本就没有刷新,逗你爹玩儿呢. 不过幸好,这该死的缓存是可以关闭的. F12 ...

  5. 设计模式之美:Template Method(模板方法)

    索引 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):Template Method 模式结构样式代码. 意图 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中. Templat ...

  6. [.net 面向对象编程基础] (8) 基础中的基础——修饰符

    [.net 面向对象编程基础] (8) 基础中的基础——修饰符 在进入C#面向对象核心之前,我们需要先对修饰符有所了解,其实我们在前面说到变量和常量的时候,已经使用了修饰符,并且说明了变量和常量的修改 ...

  7. jQuery为哪般去掉了浏览器检测

    由于做HTML5相关的项目,许多前卫时髦的前端技术就需要考虑一下IE是否支持.要是在以前,可以很方便地调用jQuery的jQuery.browser来实现. If(jQuery.browser.msi ...

  8. Redis教程(十二):服务器管理命令总结

    转载于:http://www.itxuexiwang.com/a/shujukujishu/redis/2016/0216/140.html 一.概述: Redis在设计之初就被定义为长时间不间断运行 ...

  9. iOS开发中数组常用的五种遍历方式

    随着iOS的不断发展,apple也不断推出性能更高的数组遍历方式,下面将对熟悉的五种遍历方式进行列举. 首先定义一个数组,并获取数组长度 NSArray *array=@[",]; NSIn ...

  10. IDE:Eclipse查看接口实现类快捷键

    1.打开接口类 2.双击接口名选中 3.Ctrl+T,打开接口实现类