Fixing Razor templates invalidation

This commit is contained in:
Sebastien Ros
2013-12-12 17:43:53 -08:00
parent 14a1eb0414
commit ca5334c016
11 changed files with 82 additions and 87 deletions

View File

@@ -15,14 +15,15 @@ using Orchard.Utility.Extensions;
namespace Orchard.Templates.Drivers {
public class ShapePartDriver : ContentPartDriver<ShapePart> {
private readonly IEnumerable<ITemplateProcessor> _processors;
private readonly IRazorTemplateCache _cache;
private readonly ITemplateService _service;
private readonly IRazorTemplateHolder _templateHolder;
private readonly ITransactionManager _transactions;
public ShapePartDriver(IEnumerable<ITemplateProcessor> processors, IRazorTemplateCache cache, ITemplateService service,ITransactionManager transactions) {
public ShapePartDriver(
IEnumerable<ITemplateProcessor> processors,
IRazorTemplateHolder templateHolder,
ITransactionManager transactions) {
_processors = processors;
_cache = cache;
_service = service;
_templateHolder = templateHolder;
_transactions = transactions;
T = NullLocalizer.Instance;
}
@@ -51,7 +52,7 @@ namespace Orchard.Templates.Drivers {
try {
var processor = _processors.FirstOrDefault(x => String.Equals(x.Type, part.Language, StringComparison.OrdinalIgnoreCase));
processor.Verify(part.Template);
_cache.Set(part.Name, part.Template);
_templateHolder.Set(part.Name, part.Template);
}
catch (Exception ex) {
updater.AddModelError("", T("Template processing error: {0}", ex.Message));

View File

@@ -1,16 +1,20 @@
using Orchard.Caching;
using Orchard.Compilation.Razor;
using Orchard.ContentManagement.Handlers;
using Orchard.Data;
using Orchard.Templates.Models;
using Orchard.Templates.Services;
namespace Orchard.Templates.Handlers {
public class ShapePartHandler : ContentHandler {
public ShapePartHandler(IRepository<ShapePartRecord> repository, ISignals signals) {
private readonly IRazorTemplateHolder _razorTemplateHolder;
public ShapePartHandler(
IRepository<ShapePartRecord> repository,
IRazorTemplateHolder razorTemplateHolder) {
_razorTemplateHolder = razorTemplateHolder;
Filters.Add(StorageFilter.For(repository));
OnGetContentItemMetadata<ShapePart>((ctx, part) => ctx.Metadata.DisplayText = part.Name);
OnCreated<ShapePart>((ctx, part) => signals.Trigger(DefaultTemplateService.TemplatesSignal));
OnUpdated<ShapePart>((ctx, part) => _razorTemplateHolder.Set(part.Name, part.Template));
}
}
}

View File

@@ -12,8 +12,6 @@ using Orchard.Templates.Models;
namespace Orchard.Templates.Services {
public class DefaultTemplateService : ITemplateService {
public const string TemplatesSignal = "Orchard.Templates";
private readonly IShapeFactory _shapeFactory;
private readonly IDisplayHelperFactory _displayHelperFactory;
private readonly IWorkContextAccessor _workContextAccessor;

View File

@@ -16,7 +16,6 @@ using Orchard.Themes.Models;
namespace Orchard.Templates.Services {
public class RazorTemplateProcessor : TemplateProcessorImpl {
private readonly IRazorCompiler _compiler;
private readonly IRazorTemplateCache _cache;
private readonly ISiteService _siteService;
private readonly IHttpContextAccessor _hca;
@@ -24,9 +23,8 @@ namespace Orchard.Templates.Services {
get { return "Razor"; }
}
public RazorTemplateProcessor(IRazorCompiler compiler, IRazorTemplateCache cache, ISiteService siteService, IHttpContextAccessor hca) {
public RazorTemplateProcessor(IRazorCompiler compiler, ISiteService siteService, IHttpContextAccessor hca) {
_compiler = compiler;
_cache = cache;
_siteService = siteService;
_hca = hca;
Logger = NullLogger.Instance;

View File

@@ -15,13 +15,13 @@ using Orchard.Themes.Models;
namespace Orchard.Templates.Services {
public class TemplateBindingStrategy : IShapeTableProvider {
private readonly IWorkContextAccessor _wca;
private readonly ICacheManager _cache;
private readonly ISignals _signals;
private readonly IRazorTemplateHolder _templateProvider;
public TemplateBindingStrategy(IWorkContextAccessor wca, ICacheManager cache, ISignals signals) {
public TemplateBindingStrategy(
IWorkContextAccessor wca,
IRazorTemplateHolder templateProvider) {
_wca = wca;
_cache = cache;
_signals = signals;
_templateProvider = templateProvider;
}
public void Discover(ShapeTableBuilder builder) {
@@ -31,7 +31,6 @@ namespace Orchard.Templates.Services {
private void BuildShapes(ShapeTableBuilder builder) {
var templateService = _wca.GetContext().Resolve<ITemplateService>();
var templateCache = _wca.GetContext().Resolve<IRazorTemplateCache>();
var siteService = _wca.GetContext().Resolve<ISiteService>();
var extensionManager = _wca.GetContext().Resolve<IExtensionManager>();
@@ -49,28 +48,23 @@ namespace Orchard.Templates.Services {
Priority = int.MaxValue
};
var shapes = _cache.Get(
DefaultTemplateService.TemplatesSignal,
ctx => {
ctx.Monitor(_signals.When(DefaultTemplateService.TemplatesSignal));
return templateService
.GetTemplates()
.Select(r => new {
r.Name,
r.Language,
r.Template })
.ToList();
});
var shapes = templateService.GetTemplates().Select(r =>
new {
r.Name,
r.Language,
r.Template
})
.ToList();
foreach (var record in shapes) {
templateCache.Set(record.Name, record.Template);
_templateProvider.Set(record.Name, record.Template);
var shapeType = AdjustName(record.Name);
builder.Describe(shapeType)
.From(new Feature { Descriptor = hackedDescriptor })
.BoundAs("Template::" + shapeType,
descriptor => context => {
var template = templateCache.Get(record.Name);
var template = _templateProvider.Get(record.Name);
return template != null ? PerformInvoke(context, record.Name, record.Language, template) : new HtmlString("");
});
}

View File

@@ -1,7 +1,7 @@
using System.Collections.Generic;
namespace Orchard.Compilation {
public interface ICompiler{
public interface ICompiler : IDependency {
object Compile(string code, IDictionary<string, object> parameters);
T Compile<T>(string code, IDictionary<string, object> parameters);
}

View File

@@ -1,5 +1,5 @@
namespace Orchard.Compilation.Razor {
public interface IRazorTemplateCache {
public interface IRazorTemplateHolder : ISingletonDependency {
string Get(string name);
void Set(string name, string template);
}

View File

@@ -8,7 +8,6 @@ using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Web.Razor;
using System.Web.Razor.Generator;
using Microsoft.CSharp;
using Orchard.Caching;
using Orchard.Logging;
@@ -17,25 +16,51 @@ using Orchard.Utility.Extensions;
namespace Orchard.Compilation.Razor {
public class RazorCompiler : IRazorCompiler {
private readonly ICacheManager _cache;
private readonly IWorkContextAccessor _wca;
const string DynamicallyGeneratedClassName = "RazorTemplate";
const string NamespaceForDynamicClasses = "Orchard.Compilation.Razor";
private readonly ISignals _signals;
private const string DynamicallyGeneratedClassName = "RazorTemplate";
private const string NamespaceForDynamicClasses = "Orchard.Compilation.Razor";
private const string ForceRecompile = "Razor.ForceRecompile";
private static readonly string[] DefaultNamespaces = {
"System",
"System.IO",
"System.Linq",
"System.Collections",
"System.Collections.Generic",
"System.Dynamic",
"System.Text",
"System.Web",
"System.Web.Mvc",
"System.Web.Mvc.Html",
"System.Web.Mvc.Ajax",
"System.Web.UI",
"System.Web.Routing",
"Orchard.Compilation.Razor",
"Orchard.ContentManagement",
"Orchard.DisplayManagement",
"Orchard.DisplayManagement.Shapes",
"Orchard.Security.Permissions",
"Orchard.UI.Resources",
"Orchard.Security",
"Orchard.Mvc.Spooling",
"Orchard.Mvc.Html"
};
public RazorCompiler(ICacheManager cache, IWorkContextAccessor wca) {
public RazorCompiler(
ICacheManager cache,
ISignals signals) {
_cache = cache;
_wca = wca;
_signals = signals;
Logger = NullLogger.Instance;
}
ILogger Logger { get; set; }
private ILogger Logger { get; set; }
public IRazorTemplateBase<TModel> CompileRazor<TModel>(string code, string name, IDictionary<string, object> parameters) {
return (RazorTemplateBase<TModel>)Compile(code, name, typeof(TModel), parameters);
return (RazorTemplateBase<TModel>) Compile(code, name, typeof (TModel), parameters);
}
public IRazorTemplateBase CompileRazor(string code, string name, IDictionary<string, object> parameters) {
return (IRazorTemplateBase)Compile(code, name, null, parameters);
return (IRazorTemplateBase) Compile(code, name, null, parameters);
}
public object Compile(string code, IDictionary<string, object> parameters) {
@@ -47,15 +72,12 @@ namespace Orchard.Compilation.Razor {
}
private object Compile(string code, string name, Type modelType, IDictionary<string, object> parameters) {
ISignals signals = _wca.GetContext().TryResolve(out signals) ? signals : null;
var cacheKey = name ?? GetHash(code);
var cacheKey = (name ?? DynamicallyGeneratedClassName) + GetHash(code);
var generatedClassName = name != null ? name.Strip(c => !c.IsLetter() && !Char.IsDigit(c)) : DynamicallyGeneratedClassName;
var assembly = _cache.Get(cacheKey, ctx => {
if (signals != null) {
ctx.Monitor(signals.When(ForceRecompile));
}
_signals.When(ForceRecompile);
var modelTypeName = "dynamic";
var reader = new StringReader(code);
@@ -81,32 +103,7 @@ namespace Orchard.Compilation.Razor {
DefaultNamespace = NamespaceForDynamicClasses
};
var namespaces = new List<string> {
"System",
"System.IO",
"System.Linq",
"System.Collections",
"System.Collections.Generic",
"System.Dynamic",
"System.Text",
"System.Web",
"System.Web.Mvc",
"System.Web.Mvc.Html",
"System.Web.Mvc.Ajax",
"System.Web.UI",
"System.Web.Routing",
"Orchard.Compilation.Razor",
"Orchard.ContentManagement",
"Orchard.DisplayManagement",
"Orchard.DisplayManagement.Shapes",
"Orchard.Security.Permissions",
"Orchard.UI.Resources",
"Orchard.Security",
"Orchard.Mvc.Spooling",
"Orchard.Mvc.Html"
};
foreach (var n in namespaces) {
foreach (var n in DefaultNamespaces) {
host.NamespaceImports.Add(n);
}
@@ -119,16 +116,17 @@ namespace Orchard.Compilation.Razor {
return assembly.CreateInstance(NamespaceForDynamicClasses + "." + generatedClassName);
}
public static string GetHash(string value)
{
public static string GetHash(string value) {
var data = Encoding.ASCII.GetBytes(value);
var hashData = new SHA1Managed().ComputeHash(data);
var hashData = new MD5CryptoServiceProvider().ComputeHash(data);
return hashData.Aggregate(string.Empty, (current, b) => current + b.ToString("X2"));
var strBuilder = new StringBuilder();
hashData.Aggregate(strBuilder, (current, b) => strBuilder.Append(b));
return strBuilder.ToString();
}
private static Assembly CreateCompiledAssemblyFor(CodeCompileUnit unitToCompile, string templateName)
{
private static Assembly CreateCompiledAssemblyFor(CodeCompileUnit unitToCompile, string templateName) {
var compilerParameters = new CompilerParameters();
compilerParameters.ReferencedAssemblies.AddRange(AppDomain.CurrentDomain
.GetAssemblies()

View File

@@ -1,10 +1,10 @@
using System.Collections.Concurrent;
namespace Orchard.Compilation.Razor {
public class RazorTemplateCache : IRazorTemplateCache {
public class RazorTemplateHolder : IRazorTemplateHolder {
private readonly ConcurrentDictionary<string, string> _cache;
public RazorTemplateCache() {
public RazorTemplateHolder() {
_cache = new ConcurrentDictionary<string, string>();
}
public string Get(string name) {

View File

@@ -9,6 +9,7 @@ using System.Web.Mvc;
using Autofac;
using Autofac.Configuration;
using Orchard.Caching;
using Orchard.Compilation.Razor;
using Orchard.Data;
using Orchard.Environment.AutofacUtil;
using Orchard.Environment.Configuration;
@@ -67,6 +68,7 @@ namespace Orchard.Environment {
builder.RegisterType<ViewsBackgroundCompilation>().As<IViewsBackgroundCompilation>().SingleInstance();
builder.RegisterType<DefaultExceptionPolicy>().As<IExceptionPolicy>().SingleInstance();
builder.RegisterType<DefaultCriticalErrorProvider>().As<ICriticalErrorProvider>().SingleInstance();
//builder.RegisterType<RazorTemplateCache>().As<IRazorTemplateProvider>().SingleInstance();
RegisterVolatileProvider<WebSiteFolder, IWebSiteFolder>(builder);
RegisterVolatileProvider<AppDataFolder, IAppDataFolder>(builder);

View File

@@ -153,7 +153,7 @@
<Compile Include="Compilation\ICompiler.cs" />
<Compile Include="Compilation\Razor\RazorModule.cs" />
<Compile Include="Compilation\Razor\IRazorCompiler.cs" />
<Compile Include="Compilation\Razor\IRazorTemplateCache.cs" />
<Compile Include="Compilation\Razor\IRazorTemplateHolder.cs" />
<Compile Include="Compilation\Razor\RazorCompiler.cs" />
<Compile Include="Compilation\Razor\RazorTemplateBase.cs" />
<Compile Include="Compilation\Razor\RazorTemplateCache.cs" />