文档章节

逃脱Asp.Net MVC框架的枷锁,使用Razor视图引擎

予沁安
 予沁安
发布于 2012/11/26 23:35
字数 982
阅读 7708
收藏 45

更多背景参看
前传:
Razor视图引擎浅析
后续:  eLiteWeb框架MVC(Model-View-Command) 机制解析

 

为什么要这么做?

1.  Asp.Net MVC 其实也不是太好
2. 我有自己的敏捷Web框架, 仍然想用Razor引擎
3. 动态编译很有意思,这也是将来的一个趋势,如果有人有兴趣,我倒是很想写写这方面的内容.

可是也有这些想法的人并不多,找来找去,这方面的资料和论述极其之少。与其临渊羡鱼,不如退而结网。自己动手,丰衣足食。


如Razor引擎浅析所述,Razor的两大主要功能,模板文件和动态编译器。我们能不能单纯就要而且只要这俩主要特性? 其它那些智能查找视图文件等,虽不能说是垃圾,也是束缚手脚的条条框框,我完全可以自己做,失去的是一条绳索,获得是整个世界。
保持模板功能,特别是设计时智能语法支持,很简单,创建项目时选择MVC项目,然后把其它MVC相关的引用删掉只剩下Razor就好了。
编译? 你根本就找不到这一段代码,被淹没在大量的辅助代码中。幸好,我这里已经找到了,简化修改之后,就剩下了了几行,你就可以直接使用在甚至不必是Web项目中。

(本文版权属于© 2012 - 2013 予沁安 | 转载请注明作者和出处WangHaoBlog.com

首先, 用到的Razor域名空间。

using System.Web.Razor;
using System.Web.Razor.Generator;
using System.Web.Razor.Parser;

第一步,动态编译:解析视图文件,生成代码,是的,生成代码,先。Razor的语法可以说是私有语法,需要先生成标准代码,然后才编译,生成我们熟悉的C#类Type。需要注意的是,我下面代码用的模板基类是我自己的TeamplateBase,后面会给出简单实现,当然,好处就是灵活性。你也可以直接用Asp.Net MVC的System.Web.Mvc.WebViewPage, 不过我没有试过,也许会有其他问题,不能保证。

public static Type Compile<T>(string template_path)
        {
            //准备临时类名,读取模板文件和Razor代码生成器
            var class_name = "c" + Guid.NewGuid().ToString("N");
            var base_type = typeof(TemplateBase<>).MakeGenericType(typeof(T));
            var template = File.ReadAllText(template_path);

            var host = new RazorEngineHost(new CSharpRazorCodeLanguage(), () => new HtmlMarkupParser())
                           {

                               DefaultBaseClass = base_type.FullName,
                               DefaultClassName = class_name,
                               DefaultNamespace = "YourNameSpace.dynamic",
                               GeneratedClassContext =
                                   new GeneratedClassContext("Execute", "Write", "WriteLiteral", "WriteTo",
                                                             "WriteLiteralTo",
                                                             "YourNameSpace.TemplateBase")

                           };
            host.NamespaceImports.Add("System");
            host.NamespaceImports.Add("YourNameSpaces");
            
            //生成代码
            CodeCompileUnit code;
            using (var reader = new StringReader(template)) {
                var generatedCode = new RazorTemplateEngine(host).GenerateCode(reader);
                code = generatedCode.GeneratedCode;
            }
            //准备编译参数
            var @params = new CompilerParameters
            {
                IncludeDebugInformation = false,
                TempFiles = new TempFileCollection(AppDomain.CurrentDomain.DynamicDirectory),
                CompilerOptions = "/target:library /optimize",
                GenerateInMemory = false
            };

            var assemblies = AppDomain.CurrentDomain
               .GetAssemblies()
               .Where(a => !a.IsDynamic)
               .Select(a => a.Location)
               .ToArray();
            @params.ReferencedAssemblies.AddRange(assemblies);

            //编译
            var provider = new CSharpCodeProvider();
            var compiled = provider.CompileAssemblyFromDom(@params, code);

            if (compiled.Errors.Count > 0) {
                var compileErrors = string.Join("\r\n", compiled.Errors.Cast<object>().Select(o => o.ToString()));
                throw new ApplicationException("Failed to compile Razor:" + compileErrors);
            }

            //编译成功后, 返回编译后的动态Type
            return compiled.CompiledAssembly.GetType("Skight.Arch.Presentation.Web.Core.ViewEngins.Razor.dynamic." + class_name);


        }

第二步就简单多了,就和任何静态类一样,用反射创建实例,然后复制Model对象执行模板,最后输出结果是,就自动吧Model类的数据嵌入了。

 

public static string Render<T>(T model,string template_path)
        {
            var type = Compile<T>(template_path);
            //创建视图实例
            var instance = (TemplateBase<T>)Activator.CreateInstance(type);

            //执行模板(把数据嵌入文件)
            instance.Model = model;
            instance.Execute();
            //输出最终结果
            var result = instance.Result;

            return result;
        }

最后,看看视图模板类,一个基类和一个泛型基类,后者用于前类型Model

public abstract class TemplateBase
    {
        public string Layout { get; set; }
        public UrlHelper Url { get; set; }
        public Func<string> RenderBody { get; set; }
        public string Path { get; internal set; }
        public string Result { get { return Writer.ToString(); } }

        protected TemplateBase()
        {
        }

        public TextWriter Writer
        {
            get
            {
                if(writer==null)
                {writer = new StringWriter();
                }
                return writer;
            }
            set { 
                writer = value;
            }
        }

        private TextWriter writer;

        public void Clear() {
           Writer.Flush();
        }

        public virtual void Execute() { }

        public void Write(object @object) {
            if (@object == null) {
                return;
            }
            Writer.Write(@object);
        }

        public void WriteLiteral(string @string) {
            if (@string == null) {
                return;
            }
            Writer.Write(@string);
        }

        public static void WriteLiteralTo(TextWriter writer, string literal) {
            if (literal == null) {
                return;
            }
            writer.Write(literal);
        }

        public static void WriteTo(TextWriter writer, object obj) {
            if (obj == null) {
                return;
            }
            writer.Write(obj);
        }
    }
    public abstract class TemplateBase<T> :TemplateBase
    {
        public T Model { get; set; }             
    }

© 著作权归作者所有

予沁安

予沁安

粉丝 96
博文 23
码字总数 31905
作品 3
其他
架构师
私信 提问
加载中

评论(33)

予沁安
予沁安 博主

引用来自“kiyeer”的评论

引用来自“予沁安”的评论

引用来自“kiyeer”的评论

你好,有具体的实例吗,我是菜鸟,想学习一下。

完成Razor视图引擎的调用联系,现在可以简单完成:Url提交=》解析得到处理该Url的Command =》 Command调用View显示Model => Razor模板页根据传入的Model生成最终页面。

谢谢。

http://my.oschina.net/wonner/blog/99632
kiyeer
kiyeer

引用来自“予沁安”的评论

引用来自“kiyeer”的评论

你好,有具体的实例吗,我是菜鸟,想学习一下。

完成Razor视图引擎的调用联系,现在可以简单完成:Url提交=》解析得到处理该Url的Command =》 Command调用View显示Model => Razor模板页根据传入的Model生成最终页面。

谢谢。
予沁安
予沁安 博主

引用来自“kiyeer”的评论

你好,有具体的实例吗,我是菜鸟,想学习一下。

完成Razor视图引擎的调用联系,现在可以简单完成:Url提交=》解析得到处理该Url的Command =》 Command调用View显示Model => Razor模板页根据传入的Model生成最终页面。
Dimension
Dimension

引用来自“罗格林”的评论

自荐一个Java版的Razor引擎:Rythm (http://www.oschina.net/p/rythm)

特点:

1. 和razor一样,对开发人员非常友好,简单易用
2. 好效能,速度是velocity的3倍。如果开启缓存的话,就提升的很恐怖了,比手工写StringBuilder拼接还要快。

项目驻站:https://github.com/greenlaw110/rythm/
在线演示:http://rythmengine.com/
在线文档:http://www.playframework.org/modules/rythm-1.0.0-20121110a/home (虽然是play-rythm的,但大部分都时候纯粹的rythm使用环境)

网友在其基础上开发的spring插件:https://github.com/lawrence0819/spring-web-rythm-template

QQ群:37893470

比手写StringBuilder拼接还要快?貌似很强大
予沁安
予沁安 博主

引用来自“WangSega”的评论

學習了, 如果有時間像前輩請教了

互相交流。
W
WangSega
學習了, 如果有時間像前輩請教了
予沁安
予沁安 博主

引用来自“kiyeer”的评论

你好,有具体的实例吗,我是菜鸟,想学习一下。

正在做eLiteWeb 请关注
kiyeer
kiyeer
你好,有具体的实例吗,我是菜鸟,想学习一下。
予沁安
予沁安 博主

引用来自“周文凯”的评论

不是MVC的模式,也可以用?

当然可以,就当作一个模板编译器
周文凯
周文凯
不是MVC的模式,也可以用?
ASP.NET Core 入门教程 5、ASP.NET Core MVC 视图传值入门

一、前言 1、本教程主要内容 ASP.NET Core MVC 视图引擎(Razor)简介 ASP.NET Core MVC 视图(Razor)ViewData使用示例 ASP.NET Core MVC 视图(Razor)ViewBag使用示例 ASP.NET Core NVC 视图(Ra...

ken的杂谈
2018/11/09
0
0
自己动手做框架—MVC+Front Controller

在我前面一篇博文《逃脱Asp.Net MVC框架的枷锁,使用Razor视图引擎》发表之后,很多人关心,脱离了之后怎么办?那么这可以说是它的续篇了。 同时,这也是eLiteWeb开源软件的一部分。 MVC + Fron...

予沁安
2013/01/03
0
12
1.开始学习ASP.NET MVC

Hello,大家好! 好久没有开始记录博客了,是时候开始分享一下了,这个系列主要为零基础的同学,量身打造的。废话不多说,我们开干! 什么是ASP.NET MVC MVC(Model-View-Controller)--[模型--视...

灰太狼的梦想
02/27
0
0
asp.net core系列 40 MVC 介绍与详细示例

一. MVC介绍   MVC架构模式有助于实现关注点分离。视图和控制器均依赖于模型。 但是,模型既不依赖于视图,也不依赖于控制器。 这是分离的一个关键优势。 这种分离允许模型独立于可视化展示...

花阴偷移
03/11
0
0
Nancy(二)Razor引擎的Layout和部分视图

母版(Layout)和用户控件(部分视图)在任何一个成熟的UI表现框架上是少不了的特性了,如果没有这两个特性,复制粘贴的工作就少不了了。 在了解到Nancy的时候,我同样是迫不及待的想看看是否...

李朝强
2015/12/11
581
0

没有更多内容

加载失败,请刷新页面

加载更多

mac环境编译facets

facets是Google开源的数据可视化工具。首页:https://pair-code.github.io/facets/。 体验:https://colab.research.google.com/github/PAIR-code/facets/blob/master/colab_facets.ipynb#sc......

孟飞阳
32分钟前
2
0
代码保护软件VMProtect用户手册控制面板“项目”部分都有哪些功能?

VMProtect是一种很可靠的工具,可以保护应用程序代码免受分析和破解,但只有在应用程序内保护机制正确构建且没有可能破坏整个保护的严重错误的情况下,才能实现最好的效果。 【下载VMProtect...

mnrssj
37分钟前
1
0
房子在买入两年后出手要涨幅多少才能保证不亏(粗略计算)

7日年化收益率12% 属于高利贷么 首先,将年化转换为日化的1w的日收益 0.12*10000/365 = 3.19 我们看一下余额宝7日年化2.485%1w的日收益 0.02485*10000/365 = 0.68 借贷双方约定年利率 年利率...

小小明童鞋
38分钟前
105
1
rapidjson之原位解析(Insitu parse)

什么是原位解析 一种空间复杂度为O(1)的解析方式。正常解析方式需要将JSON字符串复制到其他缓冲区进行解析,这样将会消耗时间和空间复杂度。而原位解析则在JSON字符串所在的原空间进行操作,...

SibylY
39分钟前
1
0
使用gradle打包

安装包到https://gradle.org/下载 然后 将文件解压到自定文件夹,配置环境变量 新建环境变量 GRADLE_HOME,即 D:\usr\local\gradle-2.4; 修改环境变量 Path,即追加 %GRADLE_HOME%\BIN; 打包...

青峰Jun19er
42分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部