• 第四篇 基于.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

     

  • 相关阅读:
    智能安全实验室-全能优化(Guardio) 3.8.0.460:紧急修复功能列表点击“导出(/列表)”出现错误的问题
    Guardio全能优化3.2.0.400
    智能安全实验室-全能优化(Guardio) 3.8.0.482:修正部分错误
    智能安全实验室-Defendio杀马2.4.0.420-实时防护-内存防护、新浏览器导航界面
    智能安全实验室-杀马(Defendio) 2.3.0.409 :任务计划,用户可以定时对指定目标进行扫描、智能更新等
    微软同步框架入门之五使用WCF同步远程数据
    微软同步框架入门之四冲突(Conflict)检测和处理
    小A是支枪,子弹未打光之"步枪"篇
    微软同步框架入门之三分析生成的同步类文件
    微软同步框架入门之二增量和修改同步方式
  • 原文地址:https://www.cnblogs.com/eric-z/p/5102718.html
Copyright © 2020-2023  润新知