RazorLight: `CompileRenderAsync` fails to find `System.Threading.AccessControl` with AI SQL diagnostics enabled in Azure App Service
Describe the bug
Calling CompileRenderAsync:
- On embedded resource
cshtmlfiles - In an Azure App Service execution environment
- Targeting
netcoreapp2.2for the web app /netstandard2.0for a class library with the templates - With the Application Insights SQL dependency tracking enabled
Results in FileNotFoundExceptions for system reference assemblies being thrown from RazorLight, even with MvcRazorExcludeRefAssembliesFromPublishDeploy turned on. System.Threading.AccessControl is one example, System.CodeDom is another.
To Reproduce Steps to reproduce the behavior:
- Create two projects, one targeting
netstandard2.0(a class library) and a web project targetingnetcoreapp2.2 - Embed a template
cshtmlfile in the class library - Build engine like this (had to do it this way to get unit tests for rendering working):
new RazorLightEngineBuilder()
.UseEmbeddedResourcesProject(
Assembly.GetExecutingAssembly(),
rootNamespace: myModelNamespaceRelativeToAssemblyRoot)
.SetOperatingAssembly(Assembly.GetExecutingAssembly())
.Build();
- Add something that calls
CompileRenderAsynclike this:
Engine.CompileRenderAsync(EmbeddedResourceFilename, myModel);
- Set
MvcRazorExcludeRefAssembliesFromPublishDeployto false in the class library (this allows rendering to work at all with embedded templates andnetcoreapp2.2) dotnet publishthe web project, which references thenetstandard2.0class library- Deploy the project to an Azure App Service
- Enable the SQL diagnostics option:

- Call your API that renders a razor template. Observe failure. Disable the option, retry the same operation, observe success.
Expected behavior Email renders without exception
Information (please complete the following information):
- OS: Azure App Service, so I suspect Windows Server 2016/2019
- Platform: .NET Core 2.2
- RazorLight version: 2.0-beta1 (latest as of this writing?)
- Visual Studio version: N/A
Additional context I realize it’s a complicated repro, and the maintainer is doing this for free in his free time, but I hope this at least helps someone else debug this issue. I’m not sure what the SQL dependency tracking is doing to cause this issue - maybe dropping assemblies in strange places on the Azure App Service VM?
Unfortinuately, I have not been able to reproduce this issue locally on Windows or Linux functionally or by writing unit tests that I would expect to fail.
The workarounds are to disable SQL tracking, or not target netcoreapp2.2 - I know for a fact targeting net47 instead works fine, but that’s obviously not ideal.
Full stack trace:
System.IO.FileNotFoundException: Could not load file or assembly 'System.Threading.AccessControl, Version=0.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.
File name: 'System.Threading.AccessControl, Version=0.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
at System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, IntPtr ptrLoadContextBinder)
at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, IntPtr ptrLoadContextBinder)
at System.Reflection.Assembly.Load(AssemblyName assemblyRef)
at RazorLight.Compilation.DefaultMetadataReferenceManager.GetReferencedAssemblies(Assembly a, IEnumerable`1 excludedAssemblies, HashSet`1 visitedAssemblies)+MoveNext()
at RazorLight.Compilation.DefaultMetadataReferenceManager.GetReferencedAssemblies(Assembly a, IEnumerable`1 excludedAssemblies, HashSet`1 visitedAssemblies)+MoveNext()
at RazorLight.Compilation.DefaultMetadataReferenceManager.GetReferencedAssemblies(Assembly a, IEnumerable`1 excludedAssemblies, HashSet`1 visitedAssemblies)+MoveNext()
at RazorLight.Compilation.DefaultMetadataReferenceManager.GetReferencedAssemblies(Assembly a, IEnumerable`1 excludedAssemblies, HashSet`1 visitedAssemblies)+MoveNext()
at RazorLight.Compilation.DefaultMetadataReferenceManager.GetReferencedAssemblies(Assembly a, IEnumerable`1 excludedAssemblies, HashSet`1 visitedAssemblies)+MoveNext()
at System.Linq.Set`1.UnionWith(IEnumerable`1 other)
at System.Linq.Enumerable.UnionIterator`1.FillSet()
at System.Linq.Enumerable.UnionIterator`1.ToArray()
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at RazorLight.Compilation.DefaultMetadataReferenceManager.Resolve(Assembly assembly, DependencyContext dependencyContext)
at RazorLight.Compilation.DefaultMetadataReferenceManager.Resolve(Assembly assembly)
at RazorLight.Compilation.RoslynCompilationService.EnsureOptions()
at RazorLight.Compilation.RoslynCompilationService.get_ParseOptions()
at RazorLight.Compilation.RoslynCompilationService.CreateSyntaxTree(SourceText sourceText)
at RazorLight.Compilation.RoslynCompilationService.CreateCompilation(String compilationContent, String assemblyName)
at RazorLight.Compilation.RoslynCompilationService.CompileAndEmit(IGeneratedRazorTemplate razorTemplate)
at RazorLight.Compilation.RazorTemplateCompiler.CompileAndEmit(RazorLightProjectItem projectItem)
at RazorLight.Compilation.RazorTemplateCompiler.OnCacheMissAsync(String templateKey)
--- End of stack trace from previous location where exception was thrown ---
at RazorLight.EngineHandler.CompileTemplateAsync(String key)
at RazorLight.EngineHandler.CompileRenderAsync[T](String key, T model, ExpandoObject viewBag)
About this issue
- Original URL
- State: open
- Created 5 years ago
- Comments: 19
@tghamm It’s important to realize this is not our bug. This belongs with either dotnet org or with Azure App Service. The way you can troubleshoot this problem to help get Microsoft to move the ball on this problem is as follows:
Type.GetType("TypeNameThatIsFailedToBeFound").Assemblyto log the assembly location of the type as the .NET Core Runtime thinks it exists, vs. the one that the particular call graph wants loadedSystem.Runtime.Loader.AssemblyLoadContext.GetLoadContext(Type.GetType("TypeNameThatIsFailedToBeFound").Assembly)ADDITIONAL_DEPShttps://docs.microsoft.com/en-us/dotnet/core/dependency-loading/default-probing#how-are-the-properties-populated - the article doesn’t mention it but all deps.json files can be retrieved also fromSystem.AppContext.GetData(“APP_CONTEXT_DEPS_FILES”), so you should log those as well.Hi Kevin, Thanks, that is basically what I’m interested in hearing. I think rather than me spend time debugging each person’s individual set-up, it makes more sense for me to define some best practices samples people can fork off of, and then ask them, ok, which sample did you base your logic on? And you captured beautifully what you want to achieve - unit test code coverage, and deploy via web app.