Antaris / RazorEngine

Open source templating engine based on Microsoft's Razor parsing engine
http://antaris.github.io/RazorEngine
Other
2.14k stars 577 forks source link

RazorEngine throw a NotSupportedException when compiling template in Azure Function #526

Open csimone86 opened 6 years ago

csimone86 commented 6 years ago

I must compile a razor view in an azure function to send an email, but something goes wrong. I obtain the a NotSupportedException error: The given path's format is not supported.

Here my code:

private IRazorEngineService _engine;

public MyCtor(bool isTestEnvironment)
{
    TemplateServiceConfiguration configuration = new TemplateServiceConfiguration();
    configuration.Debug = isTestEnvironment;

    this._engine = RazorEngineService.Create(configuration);
}

public string GetHtmlEmailBody(string templateFileName, object emailData, string layoutFileName)
{
    //Get data type of email data
    Type emailDataType = emailData.GetType();

    string layoutFullFileName = Path.Combine(this._layoutPath, layoutFileName);
    string layoutContentString = File.ReadAllText(layoutFullFileName);
    var layout = new LoadedTemplateSource(layoutContentString, layoutFullFileName);

    this._engine.AddTemplate("layoutName", layout);

    string templateFullFileName = Path.Combine(this._templatePath, templateFileName);
    string templateContentString = File.ReadAllText(templateFullFileName);
    var template = new LoadedTemplateSource(templateContentString, templateFullFileName);

    this._engine.AddTemplate("templateName", template);

    this._engine.Compile("templateName"); //<-- Here I get the exception
    string htmlEmailBody = this._engine.Run("templateName", emailDataType, emailData);

    return htmlEmailBody;
}

Paths are similar to D:\\...\\Emails\\Templates.. I am testing locally and it does not work... I have googled and it seems that Azure Functions have some limitations in caching and in file system management, but it is not clear how can I solve the problem. I think I have same problem this person has written here

Any idea how can I solve it? There is something wrong in what I am doing?

I am using RazorEngine 3.10.0

Thank you

csimone86 commented 6 years ago

I have found the problem, downloading your code and doing reverse engineering. Problem was inside the UseCurrentAssembliesReferenceResolver class, in the GetReferences method... here the code that throws the exception:

            return CompilerServicesUtility
                   .GetLoadedAssemblies()
                   .Where(a => !a.IsDynamic && File.Exists(a.Location) && !a.Location.Contains(CompilerServiceBase.DynamicTemplateNamespace))
                   .GroupBy(a => a.GetName().Name).Select(grp => grp.First(y => y.GetName().Version == grp.Max(x => x.GetName().Version))) // only select distinct assemblies based on FullName to avoid loading duplicate assemblies
                   .Select(a => CompilerReference.From(a))
                   .Concat(includeAssemblies ?? Enumerable.Empty<CompilerReference>());

Exactly the statements that throw the exception are File.Exists(a.Location) && !a.Location.Contains(CompilerServiceBase.DynamicTemplateNamespace)). The problem is that in Azure function some assemblies are protected, so no information can be retrieved about them... (surely I must study about azure function)...

At the moment I solved writing a custom ReferenceResolver. I copied exactly the same code from the UseCurrentAssembliesReferenceResolver and I changed just the Where conditions..

So

.Where(a => !a.IsDynamic && File.Exists(a.Location) && !a.Location.Contains(CompilerServiceBase.DynamicTemplateNamespace))

became

.Where(a => !a.IsDynamic && !a.FullName.Contains("Version=0.0.0.0") && File.Exists(a.Location) && !a.Location.Contains("CompiledRazorTemplates.Dynamic"))

I am almost sure that it is not the best way to solve the problem... but now I solved it, and after two days my work is blocked I need to go on... I hope this can help someone...

KevinMellott91 commented 6 years ago

@csimone86 thanks for this information, it fixed the same error for me as well. I've applied your fix to a fork of the repo (although directly within the UseCurrentAssembliesReferenceResolver class) to make this temporary workaround easier for others.

https://github.com/KevinMellott91/RazorEngine