From af79bb24e50a2624cc9704075d0da9fd6d2d3233 Mon Sep 17 00:00:00 2001 From: Elijah Date: Thu, 20 Jan 2011 17:52:56 -1000 Subject: [PATCH] Added Medium Trust Support, Razor DLL's can now exist in the GAC or BIN Added Inline Razor Support - Caches Templates In The App_Data directory for now Taken out umbdebug from the engine, as it caches the debug content Custom Build Provider - Future Stub --- .../{Web.config => App.Config} | 9 +- .../DynamicNodeContext.cs | 2 +- .../Properties/AssemblyInfo.cs | 1 - .../RazorBuildProvider.cs | 11 +++ umbraco.MacroEngines.Juno/RazorMacroEngine.cs | 90 ++++++++++++++----- 5 files changed, 83 insertions(+), 30 deletions(-) rename umbraco.MacroEngines.Juno/{Web.config => App.Config} (64%) create mode 100644 umbraco.MacroEngines.Juno/RazorBuildProvider.cs diff --git a/umbraco.MacroEngines.Juno/Web.config b/umbraco.MacroEngines.Juno/App.Config similarity index 64% rename from umbraco.MacroEngines.Juno/Web.config rename to umbraco.MacroEngines.Juno/App.Config index bcfb6a61bc..dd0f2da6a3 100644 --- a/umbraco.MacroEngines.Juno/Web.config +++ b/umbraco.MacroEngines.Juno/App.Config @@ -9,10 +9,9 @@ - + - - + @@ -20,8 +19,8 @@ - - + + diff --git a/umbraco.MacroEngines.Juno/DynamicNodeContext.cs b/umbraco.MacroEngines.Juno/DynamicNodeContext.cs index 211fa8521e..23094807f0 100644 --- a/umbraco.MacroEngines.Juno/DynamicNodeContext.cs +++ b/umbraco.MacroEngines.Juno/DynamicNodeContext.cs @@ -5,7 +5,7 @@ using umbraco.interfaces; namespace umbraco.MacroEngines { - public abstract class DynamicNodeContext : WebPageBase, IMacroContext { + public abstract class DynamicNodeContext : WebPage, IMacroContext { private MacroModel _macro; private DynamicNode _dynamicNode; diff --git a/umbraco.MacroEngines.Juno/Properties/AssemblyInfo.cs b/umbraco.MacroEngines.Juno/Properties/AssemblyInfo.cs index 142b376615..27cda2e055 100644 --- a/umbraco.MacroEngines.Juno/Properties/AssemblyInfo.cs +++ b/umbraco.MacroEngines.Juno/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Reflection; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following diff --git a/umbraco.MacroEngines.Juno/RazorBuildProvider.cs b/umbraco.MacroEngines.Juno/RazorBuildProvider.cs new file mode 100644 index 0000000000..e76cd68eb4 --- /dev/null +++ b/umbraco.MacroEngines.Juno/RazorBuildProvider.cs @@ -0,0 +1,11 @@ +namespace umbraco.MacroEngines { + + /// + /// Stub Build Provider If Want To Implement Anything Advanced In The Future + /// Also Allows Us To Register Build Provider In Medium Trust + /// + public class RazorBuildProvider : System.Web.WebPages.Razor.RazorBuildProvider { + + } + +} diff --git a/umbraco.MacroEngines.Juno/RazorMacroEngine.cs b/umbraco.MacroEngines.Juno/RazorMacroEngine.cs index da8b3da022..2398f9e958 100644 --- a/umbraco.MacroEngines.Juno/RazorMacroEngine.cs +++ b/umbraco.MacroEngines.Juno/RazorMacroEngine.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; +using System.Threading; using System.Web; using System.Web.Compilation; using System.Web.WebPages; @@ -28,44 +28,87 @@ namespace umbraco.MacroEngines return true; } + public string GetMd5(string text) { + var x = new System.Security.Cryptography.MD5CryptoServiceProvider(); + var bs = System.Text.Encoding.UTF8.GetBytes(text); + bs = x.ComputeHash(bs); + var s = new System.Text.StringBuilder(); + foreach (var b in bs) { + s.Append(b.ToString("x2").ToLower()); + } + return s.ToString(); + } + + public string CreateInlineRazorFile(string razorSyntax, string scriptLanguage) { + if (razorSyntax == null) + throw new ArgumentNullException("razorSyntax"); + if (scriptLanguage == null) + throw new AbandonedMutexException("scriptLanguage"); + var syntaxMd5 = GetMd5(razorSyntax); + var relativePath = "~/App_Data/inlinerazor-" + syntaxMd5 + "." + scriptLanguage; + var physicalPath = IOHelper.MapPath(relativePath); + + if (File.Exists(physicalPath)) { + var created = File.GetCreationTime(physicalPath); + if (created <= DateTime.Today.AddMinutes(-10)) + File.Delete(physicalPath); + else + return relativePath; + } + using (var file = new StreamWriter(physicalPath)) { + file.Write(razorSyntax); + } + return relativePath; + } + public string ExecuteRazor(MacroModel macro, INode currentPage) { var context = HttpContext.Current; - var isDebugMode = GlobalSettings.DebugMode && HttpContext.Current.Request.QueryString["umbDebug"] != null; - var sw = new Stopwatch(); - if (isDebugMode) - sw.Start(); + var contextWrapper = new HttpContextWrapper(context); - var fileLocation = SystemDirectories.Python + "/" + macro.ScriptName; + string fileLocation = null; + if (!string.IsNullOrEmpty(macro.ScriptName)) { + //Razor Is Already Contained In A File + fileLocation = SystemDirectories.Python + "/" + macro.ScriptName; + } else if (!string.IsNullOrEmpty(macro.ScriptCode) && !string.IsNullOrEmpty(macro.ScriptLanguage)) { + //Inline Razor Syntax + fileLocation = CreateInlineRazorFile(macro.ScriptCode, macro.ScriptLanguage); + } - //Returns The Compiled System.Type + if (string.IsNullOrEmpty(fileLocation)) + return String.Empty; //No File Location + + if (fileLocation.StartsWith("~/") == false) + throw new Exception("Only Relative Paths Are Supported"); + + var physicalPath = IOHelper.MapPath(fileLocation); + if (File.Exists(physicalPath) == false) + throw new FileNotFoundException(string.Format("Razor Script Not Found At Location, {0}", fileLocation)); + + //Compile Razor - We Will Leave This To ASP.NET Compilation Engine + //Security in medium trust is strict around here, so we can only pass a relative file path + //ASP.NET Compilation Engine caches returned types var razorType = BuildManager.GetCompiledType(fileLocation); - + if (razorType == null) + throw new ArgumentException("Null Razor Compile Type Returned From The ASP.NET Compilation Engine"); + //Instantiates The Razor Script var razorObj = Activator.CreateInstance(razorType); var razorWebPage = razorObj as WebPageBase; if (razorWebPage == null) - throw new InvalidCastException("Razor Template Must Implement System.Web.WebPages.WebPageBase"); + throw new InvalidCastException("Razor Context Must Implement System.Web.WebPages.WebPageBase, System.Web.WebPages"); //inject http context - for request response - var httpContext = new HttpContextWrapper(context); - razorWebPage.Context = httpContext; + razorWebPage.Context = contextWrapper; - //inject macro and parameters + //Inject Macro Model And Parameters if (razorObj is IMacroContext) { var razorMacro = (IMacroContext)razorObj; razorMacro.SetMembers(macro, currentPage); } - //output template + //Output Razor To String var output = new StringWriter(); - if (isDebugMode) - output.Write(string.Format(@"
", macro.Alias)); - razorWebPage.ExecutePageHierarchy(new WebPageContext(httpContext, razorWebPage, null), output); - if (isDebugMode) { - sw.Stop(); - output.Write(string.Format("Taken {0}ms", sw.ElapsedMilliseconds)); - output.Write("
"); - } + razorWebPage.ExecutePageHierarchy(new WebPageContext(contextWrapper, razorWebPage, null), output); return output.ToString(); } @@ -73,14 +116,15 @@ namespace umbraco.MacroEngines try { return ExecuteRazor(macro, currentPage); } catch (Exception exception) { - HttpContext.Current.Trace.Write("Macro", string.Format("Error loading Razor Script (file: {0}) {1}", macro.Name, exception.Message)); - var loading = string.Format("
Error loading Razor Script (file: {0})
", macro.ScriptName); + HttpContext.Current.Trace.Warn("umbracoMacro", string.Format("Error Loading Razor Script (file: {0}) {1} {2}", macro.Name, exception.Message, exception.StackTrace)); + var loading = string.Format("
Error loading Razor Script {0}
", macro.ScriptName); if (GlobalSettings.DebugMode) loading = loading + exception.Message; loading = loading + "
"; return loading; } } + #endregion } } \ No newline at end of file