RazorEngine 3.7.7 - Error compiling a cached template

I am trying to find out the problem that we have recently encountered with RazorEngine 3.7.5 and higher (tried 3.7.7)

An exception:

System.ArgumentException: either install the template manager in the templates, or add the template "MySolution.Billing.Templates.Layout.cshtml"!

This occurs when trying to cache a template using the Engine.Razor.Compile method.

public void AddTemplate(string templateName, string source) { Engine.Razor.AddTemplate(templateName, source); } public void CacheTemplate(string templateName, Type type) { var templateKey = new NameOnlyTemplateKey(templateName, ResolveType.Layout, null); Engine.Razor.Compile(templateKey, type); } 

The PreloadTemplates method is called when a service containing it is created using StructureMap for instanciation. Each template is stored as an embedded resource and loaded into the RazorEngine cache, and immediately after that compiled using RazorEngine to make sure that all templates are loaded as quickly as possible.

 private void PreloadTemplates() { var embeddedResources = Assembly.GetExecutingAssembly().GetManifestResourceNames().Where(x => x.StartsWith("MySolution.Billing.Templates")).ToList(); foreach (var invoiceResource in embeddedResources) { using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(invoiceResource)) { using (var reader = new StreamReader(stream)) { var template = reader.ReadToEnd(); this._templatingService.AddTemplate(invoiceResource, template); } } } this._templatingService.CacheTemplate("MySolution.Billing.Templates.Header.cshtml", typeof(HeaderModel)); this._templatingService.CacheTemplate("MySolution.Billing.Templates.Layout.cshtml", typeof(LayoutModel)); this._templatingService.CacheTemplate("MySolution.Billing.Templates.Footer.cshtml", null); } 

RazorEngine is configured as follows

 var config = new TemplateServiceConfiguration(); config.CachingProvider = new DefaultCachingProvider(t => { }); config.DisableTempFileLocking = true; 

How we use RazorEngine, application thread

  • WCF (InvoiceQueryFacade)
    • Global.asax.cs registers StructureMap registries.
  • IInvoiceService (created by StructureMap to provide InvoiceService)
    • A service calls PreloadTemplates in it constructor

Playback Steps

We can reproduce the error almost every time by stopping IIS and starting it again and calling the WCF method. It seems that the problem is with processing the application pool or stopping IIS, because the error does not return after the WCF has β€œwarmed up”.

+5
source share
1 answer

I could find the answer on my own.

I changed my TemplatingService class as follows

 public class TemplatingService : ITemplatingService { private readonly IRazorEngineService _razorEngineService; public TemplatingService(Assembly assembly, string templatesNamespace) { var config = new TemplateServiceConfiguration(); config.TemplateManager = new EmbeddedResourceTemplateService(assembly, templatesNamespace); #if DEBUG config.Debug = true; #endif this._razorEngineService = RazorEngineService.Create(config); } public void CacheTemplate(string templateName, Type type) { var templateKey = new NameOnlyTemplateKey(templateName, ResolveType.Layout, null); this._razorEngineService.Compile(templateKey, type); } public string RunTemplate(string templateName, Type type, object model, IDictionary<string, object> dynamicViewBag = null) { var templateKey = new NameOnlyTemplateKey(templateName, ResolveType.Layout, null); return this._razorEngineService.RunCompile(templateKey, type, model, dynamicViewBag != null ? new DynamicViewBag(dynamicViewBag) : null); } } 

I started using TemplatingManager from the official website: RazorEngine string layouts and sections? and it seemed to do the trick.

 this.For<ITemplatingService>() .Singleton() .Add<TemplatingService>() .Named("invoiceTemplates") .Ctor<Assembly>("assembly").Is(billingDocumentGeneratorAssembly) .Ctor<string>("templatesNamespace").Is("MyBillingNamespace.DocumentGenerator.Invoices.Templates"); 

And I can use TemplatingService as follows

 var footerHtml = this._templatingService.RunTemplate("Footer.cshtml", null, null); var headerHtml = this._templatingService.RunTemplate("Header.cshtml", typeof(AccountStatementHeaderModel), accountStatementModel.Header); 

I hope this helps someone else.

+6
source

Source: https://habr.com/ru/post/1243424/


All Articles