在开头也是先给大家道个歉,由于最近准备婚事导致这篇文章耽误了许久,同时也谢谢老婆大人对我的支持。

  回顾上篇文章,我们重造了一个controller,这个controller中用到了视图引擎,我们的视图引擎虽然也叫Razor,但此Razor非mvc中的Razor,MVC中的Razor同样依赖于HttpContext,我们实现的Razor借用 RazorEngine。关于RazorEngine的更多介绍请参阅http://antaris.github.io/RazorEngine/。

  在上篇文章中无论是View方法还是PartialView方法,都用到了CompileView对象,我们先来看一下CompileView类的实现。

  1. /// <summary>
  2. /// 视图编译类
  3. /// </summary>
  4. public class CompileView
  5. {
  6. private static Regex layoutEx = new Regex("Layout\\s*=\\s*@?\"(\\S*)\";");//匹配视图中的layout
  7. static InvalidatingCachingProvider cache = new InvalidatingCachingProvider();
  8. static FileSystemWatcher m_Watcher = new FileSystemWatcher();
  9.  
  10. static CompileView()
  11. {
  12. var config = new TemplateServiceConfiguration();
  13. config.BaseTemplateType = typeof(HuberImplementingTemplateBase<>);
  14. config.ReferenceResolver = new HuberReferenceResolver();
  15. config.CachingProvider = cache;
  16. cache.InvalidateAll();
  17. Engine.Razor = RazorEngineService.Create(config);
  18. //添加文件修改监控,以便在cshtml文件修改时重新编译该文件
  19. m_Watcher.Path = HuberVariable.CurWebDir;
  20. m_Watcher.IncludeSubdirectories = true;
  21. m_Watcher.Filter = "*.*";
  22. m_Watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName;
  23. m_Watcher.Created += new FileSystemEventHandler(OnChanged);
  24. m_Watcher.Changed += new FileSystemEventHandler(OnChanged);
  25. m_Watcher.Deleted += new FileSystemEventHandler(OnChanged);
  26.  
  27. m_Watcher.EnableRaisingEvents = true;
  28. }
  29. //当视图被修改后清除缓存
  30. private static void OnChanged(object sender, FileSystemEventArgs e)
  31. {
  32. if (e.FullPath.EndsWith(".cshtml"))
  33. {
  34. string s = e.FullPath.Replace(HuberVariable.CurWebDir, "/");
  35.  
  36. var key = Engine.Razor.GetKey(s);
  37. cache.InvalidateCache(key);
  38. }
  39.  
  40. }
  41.  
  42. public CompileView()
  43. {
  44. }
  45.  
  46. public string RunCompile(ITemplateKey key, Type modelType, object model, DynamicViewBag viewBag)
  47. {
  48. //判断唯一视图的缓存
  49. string path = (HuberVariable.CurWebDir + key.Name).Replace(@"\\", @"\");
  50. ICompiledTemplate cacheTemplate;
  51. cache.TryRetrieveTemplate(key, null, out cacheTemplate);
  52. if (cacheTemplate == null || !cacheTemplate.Key.Name.Trim().Equals(key.Name.Trim()))
  53. {
  54. CompileViewAndLayout(key, null, model, viewBag);
  55. }
  56. //当缓存存在返回结果
  57. return Engine.Razor.RunCompile(key, null, model, viewBag);
  58. }
  59. /// <summary>
  60. /// 编译视图和层layout
  61. /// </summary>
  62. /// <param name="key">视图的唯一路径</param>
  63. /// <param name="modelType">视图类型 :视图/layout</param>
  64. /// <param name="model">页面 MODEL</param>
  65. /// <param name="viewBag">viewBag</param>
  66. public void CompileViewAndLayout(ITemplateKey key, Type modelType, object model, DynamicViewBag viewBag)
  67. {
  68. //获取视图
  69. string FullPath = (HuberVariable.CurWebDir + key.Name.Replace("/", @"\")).Replace(@"\\", @"\");
  70. string content = System.IO.File.ReadAllText(FullPath);
  71. //匹配layout
  72. var matchs = layoutEx.Matches(content);
  73. string layoutPath = string.Empty;
  74. if (matchs != null)
  75. {
  76.  
  77. foreach (Match m in matchs)
  78. {
  79. layoutPath = m.Groups[1].Value;
  80. }
  81. }
  82. if (layoutPath != string.Empty)
  83. {
  84. //添加layout到模板
  85. string FullLayoutPath = (HuberVariable.CurWebDir + layoutPath.Replace("/", @"\")).Replace(@"\\", @"\");
  86.  
  87. if (File.Exists(FullLayoutPath))
  88. {
  89. ITemplateKey layoutKey = Engine.Razor.GetKey(layoutPath, ResolveType.Layout);
  90. CompileViewAndLayout(layoutKey, null, model, viewBag);
  91. }
  92. }
  93. if (key.TemplateType == ResolveType.Layout)
  94. {
  95. Engine.Razor.AddTemplate(key, content);
  96. }
  97. else
  98. {
  99. //编译视图
  100. Engine.Razor.RunCompile(content, key, null, model);
  101. }
  102.  
  103. }
  104. }

  

  InvalidatingCachingProvider是RazorEngine对视图文件编译结果的一种缓存策略,RazorEngine提供的缓存策略还有DefaultCachingProvider,也可以自己实现一种缓存策略只要继承ICachingProvider。

  HuberImplementingTemplateBase:我们自定义的一种Razor模板标签,如“@Html.Raw”,这个例子也可以在RazorEngine官方文档中找到。我们还可以按照规则定义更多用法,下边是我的一些实现:

  1. /// <summary>页面帮助类
  2. /// A simple helper demonstrating the @Html.Raw
  3. /// </summary>
  4. /// <typeparam name="T"></typeparam>
  5. public class HuberImplementingTemplateBase<T> : TemplateBase<T>
  6. {
  7. /// <summary>
  8. /// A simple helper demonstrating the @Html.Raw
  9. /// </summary>
  10. public HuberImplementingTemplateBase()
  11. {
  12. Html = new RazorHtmlHelper();
  13. }
  14.  
  15. /// <summary>
  16. /// A simple helper demonstrating the @Html.Raw
  17. ///
  18. /// </summary>
  19. public RazorHtmlHelper Html { get; set; }
  20.  
  21. }
  22.  
  23. public class RazorHtmlHelper
  24. {
  25.  
  26. /// <summary>
  27. /// 调用Action视图
  28. /// </summary>
  29. /// <param name="actionName">action方法名称</param>
  30. /// <param name="controllerName">控制器名称</param>
  31. /// <returns></returns>
  32. public IEncodedString Action(string actionName, string controllerName)
  33. {
  34. return Action(actionName, controllerName, new { });
  35.  
  36. }
  37.  
  38. /// <summary>
  39. /// 调用Action视图
  40. /// </summary>
  41. /// <param name="actionName"></param>
  42. /// <param name="controllerName"></param>
  43. /// <param name="routeValues">传入参数</param>
  44. /// <returns></returns>
  45. public IEncodedString Action(string actionName, string controllerName, object routeValues)
  46. {
  47. RefRequestEntity paras = SetParamValue(routeValues);
  48.  
  49. var t = HuberHttpModule.CurDomainAssembly.GetType(HuberHttpModule.CurDomainAssemblyName + ".Controllers." + controllerName + "Controller");
  50. var m = t.GetMethod(actionName);
  51. object dObj = Activator.CreateInstance(t);
  52. object result = m.Invoke(dObj, new object[] { paras });
  53. return new RawString((result as RefRespondEntity).ResultContext.ToString());
  54. }
  55.  
  56. /// <summary>
  57. /// 根据model设置传入参数
  58. /// </summary>
  59. /// <param name="routeValues"></param>
  60. /// <returns></returns>
  61. private static RefRequestEntity SetParamValue(object routeValues)
  62. {
  63. RefRequestEntity paras = new RefRequestEntity();
  64.  
  65. Type t1 = routeValues.GetType();
  66. PropertyInfo[] pis = t1.GetProperties();
  67. foreach (PropertyInfo pi in pis)
  68. {
  69. paras.Request.Add(pi.Name, pi.GetValue(routeValues));
  70.  
  71. }
  72. return paras;
  73. }
  74.  
  75. public IEncodedString RenderAction(string actionName, string controllerName)
  76. {
  77. return Action(actionName, controllerName, new { });
  78. }
  79.  
  80. public IEncodedString RenderAction(string actionName, string controllerName, object routeValues)
  81. {
  82. return Action(actionName, controllerName, routeValues);
  83. }
  84.  
  85. public IEncodedString RenderPartial(string partialViewName, string controllerName)
  86. {
  87. return RenderPartial(partialViewName, controllerName, new { }, new DynamicViewBag());
  88. }
  89.  
  90. // Renders the partial view with the given view data and, implicitly, the given view data's model
  91. public IEncodedString RenderPartial(string partialViewName, string controllerName, DynamicViewBag ViewBag)
  92. {
  93. return RenderPartial(partialViewName, controllerName, new { }, ViewBag);
  94. }
  95.  
  96. // Renders the partial view with an empty view data and the given model
  97. public IEncodedString RenderPartial(string partialViewName, string controllerName, object model)
  98. {
  99. return RenderPartial(partialViewName, controllerName, model, new DynamicViewBag());
  100. }
  101.  
  102. // Renders the partial view with a copy of the given view data plus the given model
  103. /// <summary>
  104. /// 部分视图
  105. /// </summary>
  106. /// <param name="partialViewName">部分视图名称</param>
  107. /// <param name="controllerName">控制器名称</param>
  108. /// <param name="model"> model</param>
  109. /// <param name="ViewBag">ViewBag</param>
  110. /// <returns></returns>
  111. public IEncodedString RenderPartial(string partialViewName, string controllerName, object model, DynamicViewBag ViewBag)
  112. {
  113.  
  114. RefRequestEntity paras = SetParamValue(model);
  115.  
  116. var t = HuberHttpModule.CurDomainAssembly.GetType(HuberHttpModule.CurDomainAssemblyName + ".Controllers." + controllerName + "Controller");
  117. var ActionFunc = t.GetMethod(partialViewName);
  118. object dObj = Activator.CreateInstance(t);
  119.  
  120. var AddViewBageFunc = t.GetMethod("AddViewBageValues");
  121.  
  122. foreach (string key in ViewBag.GetDynamicMemberNames())
  123. {
  124.  
  125. AddViewBageFunc.Invoke(dObj, new object[] { key, Impromptu.InvokeGet(ViewBag, key) });
  126. }
  127.  
  128. object result = ActionFunc.Invoke(dObj, new object[] { paras });
  129. return new RawString((result as RefRespondEntity).ResultContext.ToString());
  130. }
  131.  
  132. }

  

   HuberReferenceResolver:我们定义的Razor中用的类库依赖。

  1. public class HuberReferenceResolver : IReferenceResolver
  2. {
  3.  
  4. static List<CompilerReference> compilerReference;
  5. static HuberReferenceResolver()
  6. {
  7. //加载本地所有类库,@using 使用
  8. compilerReference = new List<CompilerReference>();
  9. IEnumerable<string> loadedAssemblies = (new UseCurrentAssembliesReferenceResolver())
  10. .GetReferences(null, null)
  11. .Select(r => r.GetFile())
  12. .ToArray();
  13. foreach (var l in loadedAssemblies)
  14. {
  15. compilerReference.Add(CompilerReference.From(l));
  16. }
  17.  
  18. }
  19.  
  20. public string FindLoaded(IEnumerable<string> refs, string find)
  21. {
  22. return refs.First(r => r.EndsWith(System.IO.Path.DirectorySeparatorChar + find));
  23. }
  24. public IEnumerable<CompilerReference> GetReferences(TypeContext context, IEnumerable<CompilerReference> includeAssemblies)
  25. {
  26.  
  27. #region 加载依赖程序集 此处是加载所有程序集,效率需要改进
  28.  
  29. return compilerReference;
  30. #endregion
  31. }
  32. }

  

   CompileViewAndLayout()是编译视图文件的主要部分,其中有路径的转换、key的定义规则等。

    获取视图文件对应编译后的缓存key:Engine.Razor.GetKey();

      编译模板文件(即layout部分):Engine.Razor.AddTemplate();

    编译视图文件:Engine.Razor.RunCompile()。

  1. 转载请注明出处:http://www.cnblogs.com/eric-z/p/5102718.html

第四篇 基于.net搭建热插拔式web框架(RazorEngine实现)的更多相关文章

  1. 第三篇 基于.net搭建热插拔式web框架(重造Controller)

    由于.net MVC 的controller 依赖于HttpContext,而我们在上一篇中的沙箱模式已经把一次http请求转换为反射调用,并且http上下文不支持跨域,所以我们要重造一个contro ...

  2. 第二篇 基于.net搭建热插拔式web框架(沙箱的构建)

    上周五写了一个实现原理篇,在评论中看到有朋友也遇到了我的问题,真的是有种他乡遇知己的感觉,整个系列我一定会坚持写完,并在最后把代码开源到git中.上一篇文章很多人看了以后,都表示不解,觉得不知道我到底 ...

  3. 第五篇 基于.net搭建热插拔式web框架(拦截器---请求管道)

    好了,前边我们把核心内容介绍完了,接下来要做的就是拦截用户的请求,并把请求转向沙箱内. 这里我们准备通过实现一个HttpModule类来完成请求的拦截与转发.新建一个HuberHttpModule类, ...

  4. 基于.net搭建热插拔式web框架(实现原理)

    第一节:我们为什么需要一个热插拔式的web框架? 模块之间独立开发 假设我们要做一个后台管理系统,其中包括“用户活跃度”.“产品管理”."账单管理"等模块.每个模块中有自己的业务特 ...

  5. net搭建热插拔式web框架

    net搭建热插拔式web框架(重造Controller) 由于.net MVC 的controller 依赖于HttpContext,而我们在上一篇中的沙箱模式已经把一次http请求转换为反射调用,并 ...

  6. net搭建热插拔式web框架(沙箱的构建)

    net搭建热插拔式web框架(沙箱的构建) 上周五写了一个实现原理篇,在评论中看到有朋友也遇到了我的问题,真的是有种他乡遇知己的感觉,整个系列我一定会坚持写完,并在最后把代码开源到git中.上一篇文章 ...

  7. 带你手写基于 Spring 的可插拔式 RPC 框架(一)介绍

    概述 首先这篇文章是要带大家来实现一个框架,听到框架大家可能会觉得非常高大上,其实这和我们平时写业务员代码没什么区别,但是框架是要给别人使用的,所以我们要换位思考,怎么才能让别人用着舒服,怎么样才能让 ...

  8. 转-基于NodeJS的14款Web框架

    基于NodeJS的14款Web框架 2014-10-16 23:28 作者: NodeJSNet 来源: 本站 浏览: 1,399 次阅读 我要评论暂无评论 字号: 大 中 小 摘要: 在几年的时间里 ...

  9. 两个基于C++/Qt的开源WEB框架

    1.tufao 项目地址: https://github.com/vinipsmaker/tufao 主页: http://vinipsmaker.github.io/tufao/ 介绍: Tufão ...

随机推荐

  1. BZOJ3160万径人踪灭

    Description Input & Output & Sample Input & Sample Output HINT 题解: 题意即求不连续但间隔长度对称的回文串个数. ...

  2. 委托,匿名函数和lambda表达式

    很早之前就接触到了委托,但是一直对他用的不是太多,主要是本人是菜鸟,能写的比较高级的代码确实不多,但是最近在看MSDN微软的类库的时候,发现了微软的类库好多都用到了委托,于是决定好好的研究研究,加深一 ...

  3. AngularJS Scope(作用域)

    1. AngularJS Scope(作用域) Scope(作用域) 是应用在 HTML (视图) 和 JavaScript (控制器)之间的纽带. Scope 是一个对象,有可用的方法和属性. Sc ...

  4. BPM问题

    1.安装XFormDesigner后编辑界面报错 解决方法:

  5. 阿里云VPS服务器,ROS内网穿透

    Aliyun Windows Server 2008 R2中建立vpn服务器,ros中使用pptp拨号连接 2.在Aliyun服务器中,修改hosts,将内网分配的ip映射到指定的域名,在Aliyun ...

  6. Spring中配置数据源的4种形式

    不管采用何种持久化技术,都需要定义数据源.Spring中提供了4种不同形式的数据源配置方式: spring自带的数据源(DriverManagerDataSource),DBCP数据源,C3P0数据源 ...

  7. JDBC判断数据库是否插入成功

    package com.xujianyou; import java.sql.*; public class TestConnect { public static void main(String ...

  8. ContextFlyout 在10586或10240的使用

    虽然ContextFlyout只能在红石以上版本使用,但可以采用附加属性的方法手动写一个 public static class ContextFlyoutSetter { public static ...

  9. Flyout中ComboBox失效

    参见这篇文章:https://blogs.msdn.microsoft.com/wsdevsol/2016/09/14/combobox-from-an-appbarbutton-loses-mous ...

  10. Bitmap转换成BitmapImage

    public BitmapImage BitmapToBitmapImage(System.Drawing.Bitmap bitmap) { MemoryStream ms = new MemoryS ...