.net core 使用 RazorLight 静态化

using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using RazorLight.Templating;
using RazorLight.Templating.FileSystem;
using RazorLight.Caching;
using RazorLight.Templating.Embedded;
using System.Diagnostics;
using System.Reflection;
using System.Linq;
using System.Collections.Concurrent;
using RazorLight.Host.Internal;
using RazorLight;
using System.IO;
using RazorLight.Compilation;


namespace Common
{
    /// <summary>
    /// RazorLight 模板帮助类
    /// </summary>
   public static class RazorLightCommon
    {
        private static IRazorLightEngine engine = null;


        /// <summary>
/// Adds RazorLight services that resolve templates from a given <paramref name="root"/>
/// </summary>
/// <param name="services">Service collection</param>
/// <param name="root">Root views folder</param>
/// <param name="config">Configuration (can be null)</param>
public static void AddRazorLight(this IServiceCollection services, string root, Action<IEngineConfiguration> config = null)
        {
            if (services == null)
            {
                throw new ArgumentNullException(nameof(services));
            }


            if (string.IsNullOrEmpty(root))
            {
                throw new ArgumentNullException(nameof(root));
            }


            if (root.StartsWith("/"))
            {
                root = root.Substring(1);
            }
            else if (root.StartsWith("~/"))
            {
                root = root.Substring(2);
            }


            //Setup configuration
            var configuration = EngineConfiguration.Default;
            config?.Invoke(configuration);


            //Resolve root path 
            IServiceProvider serviceProvider = services.BuildServiceProvider();
            IHostingEnvironment env = serviceProvider.GetService<IHostingEnvironment>();
            string absoluteRootPath = System.IO.Path.Combine(env.ContentRootPath, root);


            services.AddTransient<ITemplateManager>(p => new FilesystemTemplateManager(absoluteRootPath));
            services.AddSingleton<ICompilerCache>(new TrackingCompilerCache(absoluteRootPath));


            services.AddSingleton<IEngineConfiguration>(configuration);
            services.AddSingleton<IEngineCore, EngineCore>();


            services.AddSingleton<IPageFactoryProvider>(p => new CachingPageFactory(
                p.GetService<IEngineCore>().KeyCompile,
                p.GetService<ICompilerCache>()));


            services.AddSingleton<IPageLookup, FilesystemPageLookup>();
            services.AddSingleton<PropertyInjector>();


            services.AddSingleton<IRazorLightEngine, RazorLightEngine>(p =>
            {
                var engine = new RazorLightEngine(
                    p.GetRequiredService<IEngineCore>(),
                    p.GetRequiredService<IPageLookup>());


                AddEngineRenderCallbacks(engine, p);


                return engine;
            });
        }


        /// <summary>
        /// Creates RazorLight services that resolves templates inside given type assembly as a EmbeddedResource
        /// </summary>
        /// <param name="services">Service collection</param>
        /// <param name="rootType">Root type where</param>
        /// <param name="config">Configuration (can be null)</param>
        public static void AddRazorLight(this IServiceCollection services, Type rootType, Action<IEngineConfiguration> config = null)
        {
            if (services == null)
            {
                throw new ArgumentNullException(nameof(services));
            }


            if (rootType == null)
            {
                throw new ArgumentNullException(nameof(services));
            }


            var configuration = EngineConfiguration.Default;
            config?.Invoke(configuration);


            services.AddSingleton<IEngineConfiguration>(configuration);


            services.AddTransient<ITemplateManager>(p => new EmbeddedResourceTemplateManager(rootType));
            services.AddSingleton<IEngineCore, EngineCore>();


            services.AddSingleton<IPageFactoryProvider>(p => new DefaultPageFactory(p.GetService<IEngineCore>().KeyCompile));
            services.AddSingleton<IPageLookup, DefaultPageLookup>();


            services.AddSingleton<IRazorLightEngine, RazorLightEngine>();
        }


        private static void AddEngineRenderCallbacks(IRazorLightEngine engine, IServiceProvider services)
        {
            var injector = services.GetRequiredService<PropertyInjector>();


            engine.Configuration.PreRenderCallbacks.Add(template => injector.Inject(template));
        }


        #region 解析视图文件(cshtml) 生成 String


        /// <summary>
        /// 解析视图文件(cshtml) 生成 String
        /// </summary>
        /// <typeparam name="TModel">泛型实体类<peparam>
        /// <param name="hostingEnv">根节点对象</param>
        /// <param name="controllerName">控制器</param>
        /// <param name="actionName">动作(Action)</param>
        /// <param name="model">实体</param>
        /// <param name="htengine">IRazorLightEngine对象</param>
        /// <param name="viewBag">viewBag</param>
        /// <returns></returns>
        public static String CreateStrByRazorView<TModel>(IHostingEnvironment hostingEnv, String controllerName, String actionName, TModel model, out IRazorLightEngine htengine,  System.Dynamic.ExpandoObject viewBag = null)
        {
            String content = "";
            string path = hostingEnv.WebRootPath;
            Directory.SetCurrentDirectory(Directory.GetParent(path).FullName);
            path = Directory.GetCurrentDirectory() + "\\views\\" + controllerName;
            if (engine == null)
            {
                engine = EngineFactory.CreatePhysical(path);
            }
            if (viewBag == null)
            {
                content = engine.Parse<TModel>(actionName + ".cshtml", model);
            }
            else
            {
                content = engine.Parse<TModel>(actionName + ".cshtml", model, viewBag);
            }
            htengine = engine;
            return content;
        }
        #endregion




        /// <summary>
        /// 解析Razor 字符串生成 字符串
        /// </summary>
        /// <typeparam name="TModel">泛型实体类</typeparam>
        /// <param name="engine">IRazorLightEngine 对象</param>
        /// <param name="content">Razor 字符串</param>
        /// <param name="model">数据模型</param>
        /// <returns></returns>
        public static String CreateStrByRazorString<TModel>(IRazorLightEngine engine, String content, TModel model)
        {
            if (!string.IsNullOrWhiteSpace(content))
            {
                content = engine.ParseString<TModel>(content, model);
            }
            return content;
        }


    }




    public class PropertyInjector
    {
        private readonly IServiceProvider services;
        private readonly ConcurrentDictionary<PropertyInfo, FastPropertySetter> _propertyCache;


        public PropertyInjector(IServiceProvider services)
        {
            if (services == null)
            {
                throw new ArgumentNullException(nameof(services));
            }


            this.services = services;
            this._propertyCache = new ConcurrentDictionary<PropertyInfo, FastPropertySetter>();
        }


        public void Inject(TemplatePage page)
        {
            if (page == null)
            {
                throw new ArgumentNullException(nameof(page));
            }


            PropertyInfo[] properties = page.GetType().GetRuntimeProperties()
               .Where(p =>
               {
                   return
                       p.IsDefined(typeof(RazorInjectAttribute)) &&
                       p.GetIndexParameters().Length == 0 &&
                       !p.SetMethod.IsStatic;
               }).ToArray();


            foreach (var property in properties)
            {
                Type memberType = property.PropertyType;
                object instance = services.GetRequiredService(memberType);


                FastPropertySetter setter = _propertyCache.GetOrAdd(property, new FastPropertySetter(property));
                setter.SetValue(page, instance);
            }
        }
    }


    public class FastPropertySetter
    {
        private static readonly MethodInfo CallPropertySetterOpenGenericMethod =
            typeof(FastPropertySetter).GetTypeInfo().GetDeclaredMethod(nameof(CallPropertySetter));


        /// <summary>
        /// Initializes a fast <see cref="FastPropertySetter"/>.
        /// </summary>
        public FastPropertySetter(PropertyInfo property)
        {
            if (property == null)
            {
                throw new ArgumentNullException(nameof(property));
            }


            Property = property;
            Name = property.Name;
        }


        private Action<object, object> _valueSetter;


        /// <summary>
        /// Gets the backing <see cref="PropertyInfo"/>.
        /// </summary>
        public PropertyInfo Property { get; }


        /// <summary>
        /// Gets (or sets in derived types) the property name.
        /// </summary>
        public virtual string Name { get; protected set; }


        /// <summary>
        /// Gets the property value setter.
        /// </summary>
        public Action<object, object> ValueSetter
        {
            get
            {
                if (_valueSetter == null)
                {
                    _valueSetter = MakeFastPropertySetter(Property);
                }


                return _valueSetter;
            }
        }


        /// <summary>
        /// Sets the property value for the specified <paramref name="instance" />.
        /// </summary>
        /// <param name="instance">The object whose property value will be set.</param>
        /// <param name="value">The property value.</param>
        public void SetValue(object instance, object value)
        {
            ValueSetter(instance, value);
        }


        /// <summary>
        /// Creates a single fast property setter for reference types. The result is not cached.
        /// </summary>
        /// <param name="propertyInfo">propertyInfo to extract the setter for.</param>
        /// <returns>a fast getter.</returns>
        /// <remarks>
        /// This method is more memory efficient than a dynamically compiled lambda, and about the
        /// same speed. This only works for reference types.
        /// </remarks>
        public static Action<object, object> MakeFastPropertySetter(PropertyInfo propertyInfo)
        {
            if (propertyInfo == null)
            {
                throw new ArgumentNullException(nameof(propertyInfo));
            }


            if (propertyInfo.DeclaringType.GetTypeInfo().IsValueType)
            {
                throw new RazorLightException("Only reference types are allowed");
            }


            MethodInfo setMethod = propertyInfo.SetMethod;
            Debug.Assert(setMethod != null);
            Debug.Assert(!setMethod.IsStatic);
            Debug.Assert(setMethod.ReturnType == typeof(void));


            ParameterInfo[] parameters = setMethod.GetParameters();
            Debug.Assert(parameters.Length == 1);


            // Instance methods in the CLR can be turned into static methods where the first parameter
            // is open over "target". This parameter is always passed by reference, so we have a code
            // path for value types and a code path for reference types.
            Type typeInput = setMethod.DeclaringType;
            Type parameterType = parameters[0].ParameterType;


            // Create a delegate TDeclaringType -> { TDeclaringType.Property = TValue; }
            Delegate propertySetterAsAction =
                setMethod.CreateDelegate(typeof(Action<,>).MakeGenericType(typeInput, parameterType));


            MethodInfo callPropertySetterClosedGenericMethod =
                CallPropertySetterOpenGenericMethod.MakeGenericMethod(typeInput, parameterType);


            Delegate callPropertySetterDelegate =
                callPropertySetterClosedGenericMethod.CreateDelegate(
                    typeof(Action<object, object>), propertySetterAsAction);


            return (Action<object, object>)callPropertySetterDelegate;
        }


        private static void CallPropertySetter<TDeclaringType, TValue>(
            Action<TDeclaringType, TValue> setter,
            object target,
            object value)
        {
            setter((TDeclaringType)target, (TValue)value);
        }
    }


    /// <summary>
    /// RazorLight 扩展类 扩展ParseString 方法
    /// </summary>
    public static class RazorLightExtensions
    {
        /// <summary>
        /// Parses a string
        /// </summary>
        /// <typeparam name="T">Type of the model</typeparam>
        /// <param name="content">Template to parse</param>
        /// <param name="model">Template model</param>
        /// <returns>Returns parsed string</returns>
        /// <remarks>Result is not cached</remarks>
        public static string ParseString<T>(this IRazorLightEngine engine, string content, T model)
        {
            return engine.ParseString(content, model, typeof(T));
        }


        /// <summary>
        /// Parses a string
        /// </summary>
        /// <param name="content">Template to parse</param>
        /// <param name="model">Template model</param>
        /// <param name="modelType">Type of the model</param>
        /// <returns></returns>
        public static string ParseString(this IRazorLightEngine engine, string content, object model, Type modelType)
        {
            if (string.IsNullOrEmpty(content))
            {
                throw new ArgumentNullException(nameof(content));
            }


            ITemplateSource templateSource = new LoadedTemplateSource(content);


            ModelTypeInfo modelTypeInfo = new ModelTypeInfo(modelType);
            CompilationResult result = engine.Core.CompileSource(templateSource, modelTypeInfo);
            result.EnsureSuccessful();


            TemplatePage page = engine.Activate(result.CompiledType);
            page.PageContext = new PageContext() { ModelTypeInfo = modelTypeInfo };


            return engine.RunTemplate(page, model);
        }
    }


    #region 使用说明


//    1,导包


//PM> Install-Package RazorLight




//    2,网站的 Startup 类下 实现注入


// public void ConfigureServices(IServiceCollection services)
//    {


//        services.AddRazorLight("/Views");
//    }








    //public class KindEditorController : Controller
    //{
    //    private  IHostingEnvironment hostingEnv;


    //    public KindEditorController(IHostingEnvironment env)
    //    {
    //        this.hostingEnv = env;
    //    }


    //    public  String Test()
    //    {
    //        RazorLightCommon.CreateStrByView<Test>(hostingEnv, "Test", "index", null,"");
    //    }


    //}


    #endregion


}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值