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

  回顾上篇文章,我们重造了一个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实现)的更多相关文章

  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. 最长不下降序列nlogn算法

    显然n方算法在比赛中是没有什么用的(不会这么容易就过的),所以nlogn的算法尤为重要. 分析: 开2个数组,一个a记原数,f[k]表示长度为f的不下降子序列末尾元素的最小值,tot表示当前已知的最长 ...

  2. phpmyadmin导入数据库大小限制修改

    phpmyadmin默认导入数据库文件大小为2M,但一般网站的数据库导出的文件都会超出这个限制,要导入超过2M的数据库文件就需要手动修改php.ini配置文件! 在php.ini文件中修改: uplo ...

  3. [LeetCode] Copy List with Random Pointer 拷贝带有随机指针的链表

    A linked list is given such that each node contains an additional random pointer which could point t ...

  4. C#进阶系列——一步一步封装自己的HtmlHelper组件:BootstrapHelper

    前言:之前学习过很多的Bootstrap组件,博主就在脑海里构思:是否可以封装一套自己Bootstrap组件库呢.再加上看到MVC的Razor语法里面直接通过后台方法输出前端控件的方式,于是打算仿照H ...

  5. [网站公告]数据库服务器IOPS跑满造成网站不能正常访问

    今年下午13:20-14:20左右,突增的访问量引发数据库服务器(阿里云RDS)IOPS跑满,造成大量请求执行缓慢,从而严重影响了网站的正常访问,给大家带来很大的麻烦,望大家谅解! 在出现故障时,当我 ...

  6. JavaScript模板引擎artTemplate.js——结语

    再次首先感谢模板的作者大神,再次放出github的地址:artTemplate性能卓越的js模板引擎 然后感谢博客园的一位前辈,他写的handlebars.js模板引擎教程,对我提供了很大的帮助,也是 ...

  7. ubuntu系统虚拟机下共享文件夹

    一般情况 1.安装: sudo apt-get install open-vm-dkms     2.挂载: sudo mount -t vmhgfs .host:/ /mnt/hgfs 用以上命令安 ...

  8. 上传和设置Mime类型

    这两天一直在忙把主页上传的事,幸亏不久前花七块钱买了一年的数据库和虚拟主机,昨天上传了自己的个人主页,发现很多问题要改,因为代码一直没整理就那么放着了,大部分东西都要重新弄,然后把本地数据库的数据迁移 ...

  9. 【转】javascript浏览器参数的操作,js获取浏览器参数

    原文地址:http://www.haorooms.com/post/js_url_canshu html5修改浏览器地址:http://www.cnblogs.com/JiangXiaoTian/ar ...

  10. CocoaPods 的简单快速安装方法

    CocoaPods 的简单快速安装方法(Setting up CocoaPods master repo 卡着不动,是因为淘宝镜像已经不能用了. 一.git clone方法安装cocoapods 镜像 ...