RazorEngine 3.7.7 — Ошибка при компиляции кэшированного шаблона

Я пытаюсь выяснить проблему, которая возникла в последнее время с RazorEngine 3.7.5 и выше (пробовал 3.7.7)

Исключение:

System.ArgumentException: либо настройте диспетчер шаблонов на шаблоны, либо добавьте шаблон «MySolution.Billing.Templates.Layout.cshtml»!

Возникает при попытке кэширования шаблона методом Engine.Razor.Compile.

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);
}

Метод PreloadTemplates вызывается, когда служба, содержащая его, создается с использованием StructureMap для создания экземпляра. Каждый шаблон хранится как встроенный ресурс и загружается в кеш RazorEngine и сразу же после этого компилируется с помощью RazorEngine, чтобы обеспечить максимально быструю загрузку всех шаблонов.

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 настроен следующим образом

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

Как мы используем RazorEngine, поток приложений

  1. WCF (InvoiceQueryFacade)
    • Global.asax.cs registers StructureMap registries
  2. IInvoiceService (Instanciated by StructureMap to provide an InvoiceService)
    • The service calls PreloadTemplates in it's constructor

Этапы воспроизведения

Мы можем воспроизвести ошибку почти каждый раз, остановив IIS и снова запустив его, а также выполнив вызов метода WCF. Кажется, это проблема с перезапуском пула приложений или остановкой IIS, потому что ошибка не возвращается после «разогрева» WCF.


person Maxime Forest    schedule 19.02.2016    source источник


Ответы (1)


В конце концов, я смог найти ответ сам.

Я изменил свой класс TemplatingService следующим образом

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);
    }
}

Я начал использовать TemplatingManager с официального сайта: строковые макеты и разделы RazorEngine? и это вроде бы сделал свое дело.

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

И я могу использовать TemplatingService следующим образом

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

Я надеюсь, что это поможет кому-то другому.

person Maxime Forest    schedule 23.02.2016