找回密码
 立即注册
首页 业界区 业界 逃脱Asp.Net MVC框架/枷锁,使用Razor视图引擎 ...

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

勺缓曜 2025-5-29 16:10:56
更多背景参看        
前传:Razor视图引擎浅析      
后续:  自己动手做框架—MVC+Front Controller
  
  为什么要这么做?      
1.  Asp.Net MVC 其实也不是太好      
2. 我有自己的敏捷Web框架, 仍然想用Razor引擎      
3. 动态编译很有意思,这也是将来的一个趋势,如果有人有兴趣,我倒是很想写写这方面的内容.      
可是也有这些想法的人并不多,找来找去,这方面的资料和论述极其之少。与其临渊羡鱼,不如退而结网。自己动手,丰衣足食。
     
如Razor引擎浅析所述,Razor的两大主要功能,模板文件和动态编译器。我们能不能单纯就要而且只要这俩主要特性? 其它那些智能查找视图文件等,虽不能说是垃圾,也是束缚手脚的条条框框,我完全可以自己做,失去的是一条绳索,获得是整个世界。      
保持模板功能,特别是设计时智能语法支持,很简单,创建项目时选择MVC项目,然后把其它MVC相关的引用删掉只剩下Razor就好了。      
编译? 你根本就找不到这一段代码,被淹没在大量的辅助代码中。幸好,我这里已经找到了,简化修改之后,就剩下了了几行,你就可以直接使用在甚至不必是Web项目中。
  (本文版权属于© 2012 - 2013 予沁安 | 转载请注明作者和出处WangHaoBlog.com)
  首先, 用到的Razor域名空间。
  1. using System.Web.Razor;
  2. using System.Web.Razor.Generator;
  3. using System.Web.Razor.Parser;
复制代码
第一步,动态编译:解析视图文件,生成代码,是的,生成代码,先。Razor的语法可以说是私有语法,需要先生成标准代码,然后才编译,生成我们熟悉的C#类Type。需要注意的是,我下面代码用的模板基类是我自己的TeamplateBase,后面会给出简单实现,当然,好处就是灵活性。你也可以直接用Asp.Net MVC的System.Web.Mvc.WebViewPage, 不过我没有试过,也许会有其他问题,不能保证。
  1.   public static Type Compile<T>(string template_path)
  2.         {
  3.             //准备临时类名,读取模板文件和Razor代码生成器
  4.             var class_name = "c" + Guid.NewGuid().ToString("N");
  5.             var base_type = typeof(TemplateBase<>).MakeGenericType(typeof(T));
  6.             var template = File.ReadAllText(template_path);
  7.             var host = new RazorEngineHost(new CSharpRazorCodeLanguage(), () => new HtmlMarkupParser())
  8.                            {
  9.                                DefaultBaseClass = base_type.FullName,
  10.                                DefaultClassName = class_name,
  11.                                DefaultNamespace = "YourNameSpace.dynamic",
  12.                                GeneratedClassContext =
  13.                                    new GeneratedClassContext("Execute", "Write", "WriteLiteral", "WriteTo",
  14.                                                              "WriteLiteralTo",
  15.                                                              "YourNameSpace.TemplateBase")
  16.                            };
  17.             host.NamespaceImports.Add("System");
  18.             host.NamespaceImports.Add("YourNameSpaces");
  19.             
  20.             //生成代码
  21.             CodeCompileUnit code;
  22.             using (var reader = new StringReader(template)) {
  23.                 var generatedCode = new RazorTemplateEngine(host).GenerateCode(reader);
  24.                 code = generatedCode.GeneratedCode;
  25.             }
  26.             //准备编译参数
  27.             var @params = new CompilerParameters
  28.             {
  29.                 IncludeDebugInformation = false,
  30.                 TempFiles = new TempFileCollection(AppDomain.CurrentDomain.DynamicDirectory),
  31.                 CompilerOptions = "/target:library /optimize",
  32.                 GenerateInMemory = false
  33.             };
  34.             var assemblies = AppDomain.CurrentDomain
  35.                .GetAssemblies()
  36.                .Where(a => !a.IsDynamic)
  37.                .Select(a => a.Location)
  38.                .ToArray();
  39.             @params.ReferencedAssemblies.AddRange(assemblies);
  40.             //编译
  41.             var provider = new CSharpCodeProvider();
  42.             var compiled = provider.CompileAssemblyFromDom(@params, code);
  43.             if (compiled.Errors.Count > 0) {
  44.                 var compileErrors = string.Join("\r\n", compiled.Errors.Cast<object>().Select(o => o.ToString()));
  45.                 throw new ApplicationException("Failed to compile Razor:" + compileErrors);
  46.             }
  47.             //编译成功后, 返回编译后的动态Type
  48.             return compiled.CompiledAssembly.GetType("Skight.Arch.Presentation.Web.Core.ViewEngins.Razor.dynamic." + class_name);
  49.         }
复制代码
第二步就简单多了,就和任何静态类一样,用反射创建实例,然后复制Model对象执行模板,最后输出结果是,就自动吧Model类的数据嵌入了。
 
  1.   public static string Render<T>(T model,string template_path)
  2.         {
  3.             var type = Compile<T>(template_path);
  4.             //创建视图实例
  5.             var instance = (TemplateBase<T>)Activator.CreateInstance(type);
  6.             //执行模板(把数据嵌入文件)
  7.             instance.Model = model;
  8.             instance.Execute();
  9.             //输出最终结果
  10.             var result = instance.Result;
  11.             return result;
  12.         }
复制代码
最后,看看视图模板类,一个基类和一个泛型基类,后者用于前类型Model
  1. public abstract class TemplateBase
  2.     {
  3.         public string Layout { get; set; }
  4.         public UrlHelper Url { get; set; }
  5.         public Func<string> RenderBody { get; set; }
  6.         public string Path { get; internal set; }
  7.         public string Result { get { return Writer.ToString(); } }
  8.         protected TemplateBase()
  9.         {
  10.         }
  11.         public TextWriter Writer
  12.         {
  13.             get
  14.             {
  15.                 if(writer==null)
  16.                 {writer = new StringWriter();
  17.                 }
  18.                 return writer;
  19.             }
  20.             set {
  21.                 writer = value;
  22.             }
  23.         }
  24.         private TextWriter writer;
  25.         public void Clear() {
  26.            Writer.Flush();
  27.         }
  28.         public virtual void Execute() { }
  29.         public void Write(object @object) {
  30.             if (@object == null) {
  31.                 return;
  32.             }
  33.             Writer.Write(@object);
  34.         }
  35.         public void WriteLiteral(string @string) {
  36.             if (@string == null) {
  37.                 return;
  38.             }
  39.             Writer.Write(@string);
  40.         }
  41.         public static void WriteLiteralTo(TextWriter writer, string literal) {
  42.             if (literal == null) {
  43.                 return;
  44.             }
  45.             writer.Write(literal);
  46.         }
  47.         public static void WriteTo(TextWriter writer, object obj) {
  48.             if (obj == null) {
  49.                 return;
  50.             }
  51.             writer.Write(obj);
  52.         }
  53.     }
  54.     public abstract class TemplateBase<T> :TemplateBase
  55.     {
  56.         public T Model { get; set; }            
  57.     }
复制代码
前传:视图引擎浅析和Razor视图引擎浅析之二

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册