Updated Razor To Use System.Web.Complication.BuildManager

This commit is contained in:
Elijah
2011-01-18 06:14:06 -10:00
parent 2fd905edb9
commit 6f00df4c85
5 changed files with 125 additions and 137 deletions

View File

@@ -0,0 +1,24 @@
using umbraco.cms.businesslogic.macro;
using umbraco.interfaces;
namespace umbraco.MacroEngines {
public abstract class DynamicNodeContext : IMacroContext {
private MacroModel _macro;
private DynamicNode _dynamicNode;
private ParameterDictionary _parameters;
public dynamic Parameters { get { return _parameters; } }
public MacroModel Macro { get { return _macro; } }
public DynamicNode Current { get { return _dynamicNode; } }
public void SetMembers(MacroModel macro, INode node) {
_macro = macro;
_dynamicNode = new DynamicNode(node);
_parameters = new ParameterDictionary(macro.Properties);
}
}
}

View File

@@ -0,0 +1,8 @@
using umbraco.cms.businesslogic.macro;
using umbraco.interfaces;
namespace umbraco.MacroEngines {
public interface IMacroContext {
void SetMembers(MacroModel macro, INode node);
}
}

View File

@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using umbraco.cms.businesslogic.macro;
namespace umbraco.MacroEngines {
public class ParameterDictionary : DynamicObject {
private readonly IEnumerable<MacroPropertyModel> _parameters;
public ParameterDictionary(IEnumerable<MacroPropertyModel> parameters) {
if (parameters == null)
throw new ArgumentNullException("parameters");
_parameters = parameters;
}
public override IEnumerable<string> GetDynamicMemberNames() {
return _parameters.Select(p => p.Key);
}
public override bool TryGetMember(GetMemberBinder binder, out object result) {
var model = _parameters.FirstOrDefault(p => p.Key == binder.Name);
if (model == null)
{
result = string.Empty;
return true;
}
result = model.Value;
return true;
}
}
}

View File

@@ -1,161 +1,83 @@
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Web;
using RazorEngine;
using RazorEngine.Templating;
using System.Web.Compilation;
using System.Web.WebPages;
using umbraco.cms.businesslogic.macro;
using umbraco.interfaces;
using umbraco.IO;
using RE = RazorEngine;
namespace umbraco.MacroEngines
{
public class RazorEngine : IMacroEngine
public abstract class RazorEngine : IMacroEngine
{
#region IMacroEngine Members
public string Name
{
get { return "Razor Engine"; }
}
public abstract string Name { get; }
public List<string> SupportedExtensions
{
get
{
var exts = new List<string> {"razor"};
return exts;
}
}
public abstract List<string> SupportedExtensions { get; }
public Dictionary<string, IMacroGuiRendering> SupportedProperties
{
public Dictionary<string, IMacroGuiRendering> SupportedProperties {
get { throw new NotImplementedException(); }
}
public bool Validate(string code, INode currentPage, out string errorMessage)
{
try
{
string parsedResult;
if (!GetResult(null, code, currentPage, out parsedResult)) {
errorMessage = parsedResult;
return false;
}
}
catch (Exception ee)
{
errorMessage = ee.ToString();
return false;
}
// clear razor compilation cache (a hack - by setting the template base type back/forward as there isn't a clear cache method)
Razor.SetTemplateBaseType(typeof (HtmlTemplateBase<>));
Razor.SetTemplateBaseType(typeof (UmbracoTemplateBase<>));
public bool Validate(string code, INode currentPage, out string errorMessage) {
errorMessage = String.Empty;
return true;
}
public string Execute(MacroModel macro, INode currentPage)
{
string template = !String.IsNullOrEmpty(macro.ScriptCode)
? macro.ScriptCode
: loadScript(IOHelper.MapPath(SystemDirectories.Python + "/" + macro.ScriptName));
string parsedResult;
GetResult(macro.CacheIdentifier, template, currentPage, out parsedResult);
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();
// if it's a file we'll monitor changes to ensure that any updates to the file clears the cache
if (String.IsNullOrEmpty(macro.ScriptCode)) {
FileMonitor.Listen(SystemDirectories.Python + "/" + macro.ScriptName, action => RazorEngine.ClearRazorCompilationCache());
var fileLocation = SystemDirectories.Python + "/" + macro.ScriptName;
//Returns The Compiled System.Type
var razorType = BuildManager.GetCompiledType(fileLocation);
//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");
//inject http context - for request response
var httpContext = new HttpContextWrapper(context);
razorWebPage.Context = httpContext;
//inject macro and parameters
if (razorObj is IMacroContext) {
var razorMacro = (IMacroContext)razorObj;
razorMacro.SetMembers(macro, currentPage);
}
return parsedResult;
//output template
var output = new StringWriter();
if (isDebugMode)
output.Write(string.Format(@"<div title=""Macro Tag: '{0}'"" style=""border: 1px solid #009;""><div style=""border: 1px solid #CCC;"">", macro.Alias));
razorWebPage.ExecutePageHierarchy(new WebPageContext(httpContext, razorWebPage, null), output);
if (isDebugMode)
{
sw.Stop();
output.Write(string.Format("<strong>Taken {0}ms<strong>", sw.ElapsedMilliseconds));
output.Write("</div>");
}
return output.ToString();
}
public string Execute(MacroModel macro, INode currentPage) {
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("<div>Error loading Razor Script (file: {0})</br/>", macro.ScriptName);
if (GlobalSettings.DebugMode)
loading = loading + exception.Message;
loading = loading + "</div>";
return loading;
}
}
#endregion
/// <summary>
/// This clears all compiled razor scripts, thus ensures that changes made to files or scripts causes a recompilation
/// </summary>
public static void ClearRazorCompilationCache()
{
Razor.SetTemplateBaseType(typeof(HtmlTemplateBase<>));
Razor.SetTemplateBaseType(typeof(UmbracoTemplateBase<>));
}
private bool GetResult(string cacheIdentifier, string template, INode currentPage, out string result)
{
try
{
Razor.SetTemplateBaseType(typeof (UmbracoTemplateBase<>));
result = Razor.Parse(template, new DynamicNode(currentPage), cacheIdentifier);
return true;
}
catch (TemplateException ee)
{
string error = ee.ToString();
if (ee.Errors.Count > 0)
{
error +=
"</p><strong>Detailed errors:</strong><br/><ul style=\"list-style-type: disc; margin: 1em 0;\">";
foreach (CompilerError err in ee.Errors)
error += string.Format("<li style=\"display: list-item;\">{0}</li>", err);
error += "</ul><p>";
}
result = string.Format(
"<div class=\"error\"><h3>Razor Macro Engine</h3><p><em>An TemplateException occured while parsing the following code:</em></p><p>{0}</p><h4 style=\"font-weight: bold; margin: 0.5em 0 0.3em 0;\">Your Razor template:</h4><code>{1}</code><h4 style=\"font-weight: bold; margin: 0.5em 0 0.3em 0;\">Cache key:</h4><p>{2}</p></div>",
error,
HttpContext.Current.Server.HtmlEncode(template),
friendlyCacheKey(cacheIdentifier));
}
catch (Exception ee)
{
result = string.Format(
"<div class=\"error\"><h3>Razor Macro Engine</h3><em>An unknown error occured while rendering the following code:</em><br /><p>{0}</p><h4 style=\"font-weight: bold; margin: 0.5em 0 0.3em 0;\">Your Razor template:</h4><code>{1}</code><h4 style=\"font-weight: bold; margin: 0.5em 0 0.3em 0;\">Cache key:</h4><p>{2}</p></div>",
ee,
HttpContext.Current.Server.HtmlEncode(template),
friendlyCacheKey(cacheIdentifier));
}
return false;
}
private string friendlyCacheKey(string cacheKey)
{
if (!String.IsNullOrEmpty(cacheKey))
return cacheKey;
return "<em>No caching defined</em>";
}
private string loadScript(string scriptName)
{
if (File.Exists(scriptName))
{
return File.ReadAllText(scriptName);
}
return String.Empty;
}
}
public abstract class UmbracoTemplateBase<T> : TemplateBase<T>
{
private object m_model;
public override T Model
{
get { return (T) m_model; }
set { m_model = value; }
}
public string ToUpperCase(string name)
{
return name.ToUpper();
}
}
}

View File

@@ -42,12 +42,6 @@
<Reference Include="Microsoft.Scripting">
<HintPath>..\foreign dlls\DLR 4.0\Microsoft.Scripting.dll</HintPath>
</Reference>
<Reference Include="RazorEngine.Core">
<HintPath>..\foreign dlls\RazorEngine.Core.dll</HintPath>
</Reference>
<Reference Include="RazorEngine.Templates">
<HintPath>..\foreign dlls\RazorEngine.Templates.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
@@ -56,6 +50,8 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\foreign dlls\System.Web.Razor.dll</HintPath>
</Reference>
<Reference Include="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="System.Xml.Linq" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Xml" />
@@ -63,6 +59,9 @@
<ItemGroup>
<Compile Include="DLRScriptingEngine.cs" />
<Compile Include="DynamicNode.cs" />
<Compile Include="DynamicNodeContext.cs" />
<Compile Include="IMacroContext.cs" />
<Compile Include="ParameterDictionary.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="RazorEngine.cs" />
<Compile Include="Scripting\MacroScript.cs" />