using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using Nancy.ViewEngines.Razor; using Nancy.ViewEngines; using Nancy.Localization; using Nancy; namespace CB.Common { public class TemplateEngine { private readonly RazorViewEngine engine; //private volatile IRenderContext renderContext;//要么增加volatile,目前选择在代码段内设置 private readonly IRazorConfiguration configuration; private readonly FileSystemViewLocationProvider fileSystemViewLocationProvider; private readonly IRootPathProvider rootPathProvider; private readonly ITextResource textResource; private readonly DiagnosticsViewResolver viewResolver; //private readonly System.Threading.ThreadLocal threadLocal; private readonly Func createContext; private TemplateEngine() { this.configuration = new CBRazorConfiguration();//new DefaultRazorConfiguration(); this.textResource = new ResourceBasedTextResource(new DefaultAssemblyProvider());//new ResourceBasedTextResource(new ResourceAssemblyProvider()); this.engine = new RazorViewEngine(this.configuration, this.textResource);//new RazorViewEngine(configuration);// this.rootPathProvider = new CPWapRootPathProvider();//new DefaultRootPathProvider(); this.fileSystemViewLocationProvider = new FileSystemViewLocationProvider(this.rootPathProvider, new DefaultFileSystemReader()); IViewCache cache = new WapViewCache();//DefaultViewCache(); //this.viewCache = new DefaultViewCache(); this.viewResolver = new DiagnosticsViewResolver(fileSystemViewLocationProvider); //this.renderContext = // new DefaultRenderContextFactory(cache, viewResolver).GetRenderContext(new ViewLocationContext() // { // Context = new NancyContext() // }); createContext = () => { return new DefaultRenderContextFactory(cache, viewResolver).GetRenderContext(new ViewLocationContext() { Context = new NancyContext() }); //return new DefaultRenderContext(viewResolver, cache, textResource, new ViewLocationContext() //{ // Context = new NancyContext() //}); }; //threadLocal = new System.Threading.ThreadLocal(createContext); } internal class CPWapRootPathProvider : IRootPathProvider { public string GetRootPath() { return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "templates", "rzs"); } } internal class DiagnosticsViewResolver : IViewResolver { private readonly FileSystemViewLocationProvider fileSystemViewLocationProvider; public DiagnosticsViewResolver(FileSystemViewLocationProvider fileSystemViewLocationProvider) { this.fileSystemViewLocationProvider = fileSystemViewLocationProvider; } public ViewLocationResult FindView(string viewName) { if (viewName.EndsWith("cshtml")) viewName = viewName.Substring(0, viewName.Length - 7); if (viewName.EndsWith("shtml")) viewName = viewName.Substring(0, viewName.Length - 6); var location = this.fileSystemViewLocationProvider.GetLocatedViews(new[] {"cshtml", "vbhtml"}) .First(r => r.Name.ToLower() == viewName.ToLower()); return location; } public ViewLocationResult GetViewLocation(string viewName, dynamic model, ViewLocationContext viewLocationContext) { return FindView(viewName); } } //for testing,can use web.config to config /// /// razor配置类 /// /// /// /// /// /// /// /// /// /// /// /// [Obsolete("使用DefaultRazorConfiguration类,可以在config中进行配置")] public class CBRazorConfiguration : IRazorConfiguration { public bool AutoIncludeModelNamespace { get { return false; } } public IEnumerable GetAssemblyNames() { return new string[] { "CB.Entity", "CB.Common", "CB.Wap", "CB.Data", "CB.Cache", "CB.Interface", "CB.Framework" }; } public IEnumerable GetDefaultNamespaces() { return new string[] { "CB.Entity", "CB.Common", "CB.Wap", "CB.Data", "CB.Cache", "CB.Interface", "CB.Framework" }; } } private volatile static TemplateEngine _templateEngine; //static TemplateEngine() //{ // _templateEngine = new TemplateEngine(); //} public static TemplateEngine Template { get { return new TemplateEngine(); /* if (_templateEngine == null) { _templateEngine = new TemplateEngine(); //System.Threading.Interlocked.CompareExchange(ref _templateEngine, new TemplateEngine(), null); } return _templateEngine;//*/ } } public Action ExecuteTemplate(string viewName, object model, IDictionary viewbag) { var renderContext = createContext();//threadLocal.Value; var hash = ((DynamicDictionary)renderContext.Context.ViewBag); hash.Clear(); if (viewbag != null && viewbag.Count > 0) { foreach (var kv in viewbag) { hash.Add(kv); } } var location = viewResolver.FindView(viewName); if (location == null) return null; var resp = this.engine.RenderView(location, model, renderContext); return resp.Contents; } public StringBuilder GetTemplateContent(string viewName, object model, IDictionary viewbag) { var ms = new MemoryStream(); var action = ExecuteTemplate(viewName, model, viewbag); if (action == null) return null; action.Invoke(ms); ms.Position = 0; var sb = new StringBuilder(); using (var reader = new StreamReader(ms)) { while (reader.Peek() > -1) { sb.Append(reader.ReadLine()); } } return sb; } //private static readonly object locker = new object(); //private readonly System.Threading.SpinLock spinlock = new System.Threading.SpinLock(); //public StringBuilder GetTemplateContent(string viewName, object model, IDictionary viewbag) //{ // var t = System.Threading.Tasks.Task.Factory.StartNew(() => // { // bool lockTaken = false; // try // { // spinlock.Enter(ref lockTaken); // return GetTemplateContent1(viewName, model, viewbag); // } // finally // { // if (lockTaken) spinlock.Exit(false); // } // }); // System.Threading.Tasks.Task.WaitAny(new System.Threading.Tasks.Task[] { t }, 1000); // return t.Result; //} } public class WapViewCache : IViewCache { private readonly System.Web.Caching.Cache webCache = System.Web.HttpRuntime.Cache; const string PrefixKey = "_Razor_Template_p_"; readonly object objLocker = new object(); public TCompiledView GetOrAdd(ViewLocationResult viewLocationResult, Func valueFactory) { if (StaticConfiguration.DisableCaches) { return valueFactory(viewLocationResult); } var key = PrefixKey + viewLocationResult.Name; object o = webCache.Get(key); if (o == null) { //lock (objLocker) //{ // if (o == null) // { // } //} o = valueFactory(viewLocationResult); var nextSecondDay = DateTime.Now.AddDays(1); nextSecondDay = DateTime.Parse(nextSecondDay.ToString("yyyy-MM-dd") + " 01:00:00"); webCache.Insert(key, o, null, System.DateTime.Now.AddHours(36), TimeSpan.Zero); } return (TCompiledView)o; } public void Remove(ViewLocationResult viewLocationResult) { if (StaticConfiguration.DisableCaches) return; var key = PrefixKey + viewLocationResult.Name; object o = webCache.Get(key); if (o != null) webCache.Remove(key); return; } } }