第四篇 基于.net搭建热插拔式web框架(RazorEngine实现)
在开头也是先给大家道个歉,由于最近准备婚事导致这篇文章耽误了许久,同时也谢谢老婆大人对我的支持。
回顾上篇文章,我们重造了一个controller,这个controller中用到了视图引擎,我们的视图引擎虽然也叫Razor,但此Razor非mvc中的Razor,MVC中的Razor同样依赖于HttpContext,我们实现的Razor借用 RazorEngine。关于RazorEngine的更多介绍请参阅http://antaris.github.io/RazorEngine/。
在上篇文章中无论是View方法还是PartialView方法,都用到了CompileView对象,我们先来看一下CompileView类的实现。
- /// <summary>
- /// 视图编译类
- /// </summary>
- public class CompileView
- {
- private static Regex layoutEx = new Regex("Layout\\s*=\\s*@?\"(\\S*)\";");//匹配视图中的layout
- static InvalidatingCachingProvider cache = new InvalidatingCachingProvider();
- static FileSystemWatcher m_Watcher = new FileSystemWatcher();
- static CompileView()
- {
- var config = new TemplateServiceConfiguration();
- config.BaseTemplateType = typeof(HuberImplementingTemplateBase<>);
- config.ReferenceResolver = new HuberReferenceResolver();
- config.CachingProvider = cache;
- cache.InvalidateAll();
- Engine.Razor = RazorEngineService.Create(config);
- //添加文件修改监控,以便在cshtml文件修改时重新编译该文件
- m_Watcher.Path = HuberVariable.CurWebDir;
- m_Watcher.IncludeSubdirectories = true;
- m_Watcher.Filter = "*.*";
- m_Watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName;
- m_Watcher.Created += new FileSystemEventHandler(OnChanged);
- m_Watcher.Changed += new FileSystemEventHandler(OnChanged);
- m_Watcher.Deleted += new FileSystemEventHandler(OnChanged);
- m_Watcher.EnableRaisingEvents = true;
- }
- //当视图被修改后清除缓存
- private static void OnChanged(object sender, FileSystemEventArgs e)
- {
- if (e.FullPath.EndsWith(".cshtml"))
- {
- string s = e.FullPath.Replace(HuberVariable.CurWebDir, "/");
- var key = Engine.Razor.GetKey(s);
- cache.InvalidateCache(key);
- }
- }
- public CompileView()
- {
- }
- public string RunCompile(ITemplateKey key, Type modelType, object model, DynamicViewBag viewBag)
- {
- //判断唯一视图的缓存
- string path = (HuberVariable.CurWebDir + key.Name).Replace(@"\\", @"\");
- ICompiledTemplate cacheTemplate;
- cache.TryRetrieveTemplate(key, null, out cacheTemplate);
- if (cacheTemplate == null || !cacheTemplate.Key.Name.Trim().Equals(key.Name.Trim()))
- {
- CompileViewAndLayout(key, null, model, viewBag);
- }
- //当缓存存在返回结果
- return Engine.Razor.RunCompile(key, null, model, viewBag);
- }
- /// <summary>
- /// 编译视图和层layout
- /// </summary>
- /// <param name="key">视图的唯一路径</param>
- /// <param name="modelType">视图类型 :视图/layout</param>
- /// <param name="model">页面 MODEL</param>
- /// <param name="viewBag">viewBag</param>
- public void CompileViewAndLayout(ITemplateKey key, Type modelType, object model, DynamicViewBag viewBag)
- {
- //获取视图
- string FullPath = (HuberVariable.CurWebDir + key.Name.Replace("/", @"\")).Replace(@"\\", @"\");
- string content = System.IO.File.ReadAllText(FullPath);
- //匹配layout
- var matchs = layoutEx.Matches(content);
- string layoutPath = string.Empty;
- if (matchs != null)
- {
- foreach (Match m in matchs)
- {
- layoutPath = m.Groups[1].Value;
- }
- }
- if (layoutPath != string.Empty)
- {
- //添加layout到模板
- string FullLayoutPath = (HuberVariable.CurWebDir + layoutPath.Replace("/", @"\")).Replace(@"\\", @"\");
- if (File.Exists(FullLayoutPath))
- {
- ITemplateKey layoutKey = Engine.Razor.GetKey(layoutPath, ResolveType.Layout);
- CompileViewAndLayout(layoutKey, null, model, viewBag);
- }
- }
- if (key.TemplateType == ResolveType.Layout)
- {
- Engine.Razor.AddTemplate(key, content);
- }
- else
- {
- //编译视图
- Engine.Razor.RunCompile(content, key, null, model);
- }
- }
- }
InvalidatingCachingProvider是RazorEngine对视图文件编译结果的一种缓存策略,RazorEngine提供的缓存策略还有DefaultCachingProvider,也可以自己实现一种缓存策略只要继承ICachingProvider。
HuberImplementingTemplateBase:我们自定义的一种Razor模板标签,如“@Html.Raw”,这个例子也可以在RazorEngine官方文档中找到。我们还可以按照规则定义更多用法,下边是我的一些实现:
- /// <summary>页面帮助类
- /// A simple helper demonstrating the @Html.Raw
- /// </summary>
- /// <typeparam name="T"></typeparam>
- public class HuberImplementingTemplateBase<T> : TemplateBase<T>
- {
- /// <summary>
- /// A simple helper demonstrating the @Html.Raw
- /// </summary>
- public HuberImplementingTemplateBase()
- {
- Html = new RazorHtmlHelper();
- }
- /// <summary>
- /// A simple helper demonstrating the @Html.Raw
- ///
- /// </summary>
- public RazorHtmlHelper Html { get; set; }
- }
- public class RazorHtmlHelper
- {
- /// <summary>
- /// 调用Action视图
- /// </summary>
- /// <param name="actionName">action方法名称</param>
- /// <param name="controllerName">控制器名称</param>
- /// <returns></returns>
- public IEncodedString Action(string actionName, string controllerName)
- {
- return Action(actionName, controllerName, new { });
- }
- /// <summary>
- /// 调用Action视图
- /// </summary>
- /// <param name="actionName"></param>
- /// <param name="controllerName"></param>
- /// <param name="routeValues">传入参数</param>
- /// <returns></returns>
- public IEncodedString Action(string actionName, string controllerName, object routeValues)
- {
- RefRequestEntity paras = SetParamValue(routeValues);
- var t = HuberHttpModule.CurDomainAssembly.GetType(HuberHttpModule.CurDomainAssemblyName + ".Controllers." + controllerName + "Controller");
- var m = t.GetMethod(actionName);
- object dObj = Activator.CreateInstance(t);
- object result = m.Invoke(dObj, new object[] { paras });
- return new RawString((result as RefRespondEntity).ResultContext.ToString());
- }
- /// <summary>
- /// 根据model设置传入参数
- /// </summary>
- /// <param name="routeValues"></param>
- /// <returns></returns>
- private static RefRequestEntity SetParamValue(object routeValues)
- {
- RefRequestEntity paras = new RefRequestEntity();
- Type t1 = routeValues.GetType();
- PropertyInfo[] pis = t1.GetProperties();
- foreach (PropertyInfo pi in pis)
- {
- paras.Request.Add(pi.Name, pi.GetValue(routeValues));
- }
- return paras;
- }
- public IEncodedString RenderAction(string actionName, string controllerName)
- {
- return Action(actionName, controllerName, new { });
- }
- public IEncodedString RenderAction(string actionName, string controllerName, object routeValues)
- {
- return Action(actionName, controllerName, routeValues);
- }
- public IEncodedString RenderPartial(string partialViewName, string controllerName)
- {
- return RenderPartial(partialViewName, controllerName, new { }, new DynamicViewBag());
- }
- // Renders the partial view with the given view data and, implicitly, the given view data's model
- public IEncodedString RenderPartial(string partialViewName, string controllerName, DynamicViewBag ViewBag)
- {
- return RenderPartial(partialViewName, controllerName, new { }, ViewBag);
- }
- // Renders the partial view with an empty view data and the given model
- public IEncodedString RenderPartial(string partialViewName, string controllerName, object model)
- {
- return RenderPartial(partialViewName, controllerName, model, new DynamicViewBag());
- }
- // Renders the partial view with a copy of the given view data plus the given model
- /// <summary>
- /// 部分视图
- /// </summary>
- /// <param name="partialViewName">部分视图名称</param>
- /// <param name="controllerName">控制器名称</param>
- /// <param name="model"> model</param>
- /// <param name="ViewBag">ViewBag</param>
- /// <returns></returns>
- public IEncodedString RenderPartial(string partialViewName, string controllerName, object model, DynamicViewBag ViewBag)
- {
- RefRequestEntity paras = SetParamValue(model);
- var t = HuberHttpModule.CurDomainAssembly.GetType(HuberHttpModule.CurDomainAssemblyName + ".Controllers." + controllerName + "Controller");
- var ActionFunc = t.GetMethod(partialViewName);
- object dObj = Activator.CreateInstance(t);
- var AddViewBageFunc = t.GetMethod("AddViewBageValues");
- foreach (string key in ViewBag.GetDynamicMemberNames())
- {
- AddViewBageFunc.Invoke(dObj, new object[] { key, Impromptu.InvokeGet(ViewBag, key) });
- }
- object result = ActionFunc.Invoke(dObj, new object[] { paras });
- return new RawString((result as RefRespondEntity).ResultContext.ToString());
- }
- }
HuberReferenceResolver:我们定义的Razor中用的类库依赖。
- public class HuberReferenceResolver : IReferenceResolver
- {
- static List<CompilerReference> compilerReference;
- static HuberReferenceResolver()
- {
- //加载本地所有类库,@using 使用
- compilerReference = new List<CompilerReference>();
- IEnumerable<string> loadedAssemblies = (new UseCurrentAssembliesReferenceResolver())
- .GetReferences(null, null)
- .Select(r => r.GetFile())
- .ToArray();
- foreach (var l in loadedAssemblies)
- {
- compilerReference.Add(CompilerReference.From(l));
- }
- }
- public string FindLoaded(IEnumerable<string> refs, string find)
- {
- return refs.First(r => r.EndsWith(System.IO.Path.DirectorySeparatorChar + find));
- }
- public IEnumerable<CompilerReference> GetReferences(TypeContext context, IEnumerable<CompilerReference> includeAssemblies)
- {
- #region 加载依赖程序集 此处是加载所有程序集,效率需要改进
- return compilerReference;
- #endregion
- }
- }
CompileViewAndLayout()是编译视图文件的主要部分,其中有路径的转换、key的定义规则等。
获取视图文件对应编译后的缓存key:Engine.Razor.GetKey();
编译模板文件(即layout部分):Engine.Razor.AddTemplate();
编译视图文件:Engine.Razor.RunCompile()。
- 转载请注明出处:http://www.cnblogs.com/eric-z/p/5102718.html
第四篇 基于.net搭建热插拔式web框架(RazorEngine实现)的更多相关文章
- 第三篇 基于.net搭建热插拔式web框架(重造Controller)
由于.net MVC 的controller 依赖于HttpContext,而我们在上一篇中的沙箱模式已经把一次http请求转换为反射调用,并且http上下文不支持跨域,所以我们要重造一个contro ...
- 第二篇 基于.net搭建热插拔式web框架(沙箱的构建)
上周五写了一个实现原理篇,在评论中看到有朋友也遇到了我的问题,真的是有种他乡遇知己的感觉,整个系列我一定会坚持写完,并在最后把代码开源到git中.上一篇文章很多人看了以后,都表示不解,觉得不知道我到底 ...
- 第五篇 基于.net搭建热插拔式web框架(拦截器---请求管道)
好了,前边我们把核心内容介绍完了,接下来要做的就是拦截用户的请求,并把请求转向沙箱内. 这里我们准备通过实现一个HttpModule类来完成请求的拦截与转发.新建一个HuberHttpModule类, ...
- 基于.net搭建热插拔式web框架(实现原理)
第一节:我们为什么需要一个热插拔式的web框架? 模块之间独立开发 假设我们要做一个后台管理系统,其中包括“用户活跃度”.“产品管理”."账单管理"等模块.每个模块中有自己的业务特 ...
- net搭建热插拔式web框架
net搭建热插拔式web框架(重造Controller) 由于.net MVC 的controller 依赖于HttpContext,而我们在上一篇中的沙箱模式已经把一次http请求转换为反射调用,并 ...
- net搭建热插拔式web框架(沙箱的构建)
net搭建热插拔式web框架(沙箱的构建) 上周五写了一个实现原理篇,在评论中看到有朋友也遇到了我的问题,真的是有种他乡遇知己的感觉,整个系列我一定会坚持写完,并在最后把代码开源到git中.上一篇文章 ...
- 带你手写基于 Spring 的可插拔式 RPC 框架(一)介绍
概述 首先这篇文章是要带大家来实现一个框架,听到框架大家可能会觉得非常高大上,其实这和我们平时写业务员代码没什么区别,但是框架是要给别人使用的,所以我们要换位思考,怎么才能让别人用着舒服,怎么样才能让 ...
- 转-基于NodeJS的14款Web框架
基于NodeJS的14款Web框架 2014-10-16 23:28 作者: NodeJSNet 来源: 本站 浏览: 1,399 次阅读 我要评论暂无评论 字号: 大 中 小 摘要: 在几年的时间里 ...
- 两个基于C++/Qt的开源WEB框架
1.tufao 项目地址: https://github.com/vinipsmaker/tufao 主页: http://vinipsmaker.github.io/tufao/ 介绍: Tufão ...
随机推荐
- BZOJ3160万径人踪灭
Description Input & Output & Sample Input & Sample Output HINT 题解: 题意即求不连续但间隔长度对称的回文串个数. ...
- 委托,匿名函数和lambda表达式
很早之前就接触到了委托,但是一直对他用的不是太多,主要是本人是菜鸟,能写的比较高级的代码确实不多,但是最近在看MSDN微软的类库的时候,发现了微软的类库好多都用到了委托,于是决定好好的研究研究,加深一 ...
- AngularJS Scope(作用域)
1. AngularJS Scope(作用域) Scope(作用域) 是应用在 HTML (视图) 和 JavaScript (控制器)之间的纽带. Scope 是一个对象,有可用的方法和属性. Sc ...
- BPM问题
1.安装XFormDesigner后编辑界面报错 解决方法:
- 阿里云VPS服务器,ROS内网穿透
Aliyun Windows Server 2008 R2中建立vpn服务器,ros中使用pptp拨号连接 2.在Aliyun服务器中,修改hosts,将内网分配的ip映射到指定的域名,在Aliyun ...
- Spring中配置数据源的4种形式
不管采用何种持久化技术,都需要定义数据源.Spring中提供了4种不同形式的数据源配置方式: spring自带的数据源(DriverManagerDataSource),DBCP数据源,C3P0数据源 ...
- JDBC判断数据库是否插入成功
package com.xujianyou; import java.sql.*; public class TestConnect { public static void main(String ...
- ContextFlyout 在10586或10240的使用
虽然ContextFlyout只能在红石以上版本使用,但可以采用附加属性的方法手动写一个 public static class ContextFlyoutSetter { public static ...
- Flyout中ComboBox失效
参见这篇文章:https://blogs.msdn.microsoft.com/wsdevsol/2016/09/14/combobox-from-an-appbarbutton-loses-mous ...
- Bitmap转换成BitmapImage
public BitmapImage BitmapToBitmapImage(System.Drawing.Bitmap bitmap) { MemoryStream ms = new MemoryS ...