toddams/RazorLight

Error when trying to render from .NET 6 project

Closed this issue · 9 comments

Describe the bug
I have RazorLight set up in a shared project that multitargets both net48 and net6.0. I have a web project that targets 4.8, and when using RazorLight via the previously mentioned shared project it works fine. I also have a console project that targets net6.0. When attempting to use the same shared project it fails with the below error.

I see that there are several bugs describing a similar error. I've tried all of the suggestions on these other issues in addition to the troubleshooting steps outlined in the readme.

Thanks in advance for the help!

To Reproduce
Setup:
RazorLightEngine razorLightEngine = new RazorLightEngineBuilder() .SetOperatingAssembly(type.Assembly) .UseFileSystemProject(templatePath) .UseMemoryCachingProvider() .Build();

Execution:
string renderedContent = await razorLightEngine.CompileRenderAsync(key, model, (ExpandoObject)ViewBag);

Expected behavior
The template is rendered without error.

Information (please complete the following information):

  • OS: Windows 10
  • Platform: .NET Framework 4.8, .NET 6
  • RazorLight version: 2.3.0
  • Are you using the OFFICIAL RazorLight package? Yes
  • Visual Studio version: Visual Studio Enterprise 17.3.6

Additional context
Quartz.SchedulerException: Job threw an unhandled exception.
---> RazorLight.Compilation.TemplateCompilationException: Failed to compile generated Razor template:
- (3:29) The type or namespace name 'Razor' does not exist in the namespace 'RazorLight' (are you missing an assembly reference?)
- (1:6) The type or namespace name 'GDIT' could not be found (are you missing a using directive or an assembly reference?)
- (25:37) The type or namespace name 'TemplatePage<>' could not be found (are you missing a using directive or an assembly reference?)
- (25:50) The type or namespace name 'LeaveNotification' could not be found (are you missing a using directive or an assembly reference?)
- (28:66) 'GeneratedTemplate.ExecuteAsync()': no suitable method found to override
- (4:4) The name 'Layout' does not exist in the current context
- (5:30) The name 'Model' does not exist in the current context
- (6:8) The name 'Model' does not exist in the current context
- (6:55) The name 'Model' does not exist in the current context
- (6:98) The name 'Model' does not exist in the current context
- (8:38) The name 'Model' does not exist in the current context
- (43:12) The name 'WriteLiteral' does not exist in the current context
- (12:38) The name 'Write' does not exist in the current context
- (12:44) The name 'Model' does not exist in the current context
- (51:12) The name 'WriteLiteral' does not exist in the current context
- (12:99) The name 'Write' does not exist in the current context
- (59:12) The name 'WriteLiteral' does not exist in the current context
- (60:12) The name 'BeginWriteAttribute' does not exist in the current context
- (15:0) The name 'WriteAttributeValue' does not exist in the current context
- (15:67) The name 'ViewBag' does not exist in the current context
- (15:84) The name 'Model' does not exist in the current context
- (68:12) The name 'EndWriteAttribute' does not exist in the current context
- (69:12) The name 'WriteLiteral' does not exist in the current context
- (15:131) The name 'Write' does not exist in the current context
- (15:175) The name 'ViewBag' does not exist in the current context
- (15:193) The name 'Model' does not exist in the current context
- (77:12) The name 'WriteLiteral' does not exist in the current context

See CompilationErrors for detailed information

     at RazorLight.Compilation.RoslynCompilationService.CompileAndEmit(IGeneratedRazorTemplate razorTemplate)
     at RazorLight.Compilation.RazorTemplateCompiler.CompileAndEmitAsync(RazorLightProjectItem projectItem)
     at RazorLight.Compilation.RazorTemplateCompiler.OnCacheMissAsync(String templateKey)
     at RazorLight.Compilation.RazorTemplateCompiler.OnCacheMissAsync(String templateKey)
     at RazorLight.EngineHandler.CompileTemplateAsync(String key)
     at RazorLight.EngineHandler.CompileRenderAsync[T](String key, T model, ExpandoObject viewBag)
     at Notifications.Jobs.JobBase`1.BuildTemplate(String template, Object model) in Source\Notifications\Jobs\JobBase.cs:line 285
     at Notifications.Jobs.Leave.NewLeave.BuildMessage() in Source\Notifications\Jobs\Leave\NewLeave.cs:line 28
     at Notifications.Jobs.Leave.NewLeave.Execute(IJobExecutionContext context) in Notifications\Jobs\Leave\NewLeave.cs:line 41
     at Quartz.Core.JobRunShell.Run(CancellationToken cancellationToken)
     --- End of inner exception stack trace --- [See nested exception: RazorLight.Compilation.TemplateCompilationException: Failed to compile generated Razor template:
  - (3:29) The type or namespace name 'Razor' does not exist in the namespace 'RazorLight' (are you missing an assembly reference?)
  - (1:6) The type or namespace name 'Project' could not be found (are you missing a using directive or an assembly reference?)
  - (25:37) The type or namespace name 'TemplatePage<>' could not be found (are you missing a using directive or an assembly reference?)
  - (25:50) The type or namespace name 'LeaveNotification' could not be found (are you missing a using directive or an assembly reference?)
  - (28:66) 'GeneratedTemplate.ExecuteAsync()': no suitable method found to override
  - (4:4) The name 'Layout' does not exist in the current context
  - (5:30) The name 'Model' does not exist in the current context
  - (6:8) The name 'Model' does not exist in the current context
  - (6:55) The name 'Model' does not exist in the current context
  - (6:98) The name 'Model' does not exist in the current context
  - (8:38) The name 'Model' does not exist in the current context
  - (43:12) The name 'WriteLiteral' does not exist in the current context
  - (12:38) The name 'Write' does not exist in the current context
  - (12:44) The name 'Model' does not exist in the current context
  - (51:12) The name 'WriteLiteral' does not exist in the current context
  - (12:99) The name 'Write' does not exist in the current context
  - (59:12) The name 'WriteLiteral' does not exist in the current context
  - (60:12) The name 'BeginWriteAttribute' does not exist in the current context
  - (15:0) The name 'WriteAttributeValue' does not exist in the current context
  - (15:67) The name 'ViewBag' does not exist in the current context
  - (15:84) The name 'Model' does not exist in the current context
  - (68:12) The name 'EndWriteAttribute' does not exist in the current context
  - (69:12) The name 'WriteLiteral' does not exist in the current context
  - (15:131) The name 'Write' does not exist in the current context
  - (15:175) The name 'ViewBag' does not exist in the current context
  - (15:193) The name 'Model' does not exist in the current context
  - (77:12) The name 'WriteLiteral' does not exist in the current context

See CompilationErrors for detailed information

     at RazorLight.Compilation.RoslynCompilationService.CompileAndEmit(IGeneratedRazorTemplate razorTemplate)
     at RazorLight.Compilation.RazorTemplateCompiler.CompileAndEmitAsync(RazorLightProjectItem projectItem)
     at RazorLight.Compilation.RazorTemplateCompiler.OnCacheMissAsync(String templateKey)
     at RazorLight.Compilation.RazorTemplateCompiler.OnCacheMissAsync(String templateKey)
     at RazorLight.EngineHandler.CompileTemplateAsync(String key)
     at RazorLight.EngineHandler.CompileRenderAsync[T](String key, T model, ExpandoObject viewBag)
     at Notifications.Jobs.JobBase`1.BuildTemplate(String template, Object model) in Source\Notifications\Jobs\JobBase.cs:line 285
     at Notifications.Jobs.Leave.NewLeave.BuildMessage() in Source\Notifications\Jobs\Leave\NewLeave.cs:line 28
     at Notifications.Jobs.Leave.NewLeave.Execute(IJobExecutionContext context) in Source\Notifications\Jobs\Leave\NewLeave.cs:line 41
     at Quartz.Core.JobRunShell.Run(CancellationToken cancellationToken)]

I think I need a sample project to help you. Can you try creating a small repro?

I failed to create a minimal solution to reproduce the problem. However, the attempt to do so allowed me to eventually fix it.

I noticed that if I create the RazorLightEngine directly within Program.cs within the console application having the problem I didn't run into the same issue. However, creating the engine from within the referenced multi-targeted class library project continued to fail.

It's also worth mentioning that this is running inside the context of a Quartz.NET scheduled job. Perhaps the context under which these jobs run has something to do with its inability to find the RazorLight dependencies.

Ultimately I resolved it by wiring up the Quartz job to use dependency injection, and injected the working instance of the engine created in Program.cs.

Thanks so much for your quick willingness to help!

Thank you for the clear explanation as to what went wrong. Have a great rest of your night.

doxxx commented

@jzabroski: I am encountering a similar problem. I have an existing templating system, that was based on an old version of RazorEngine, that I am attempting to port to .NET 6 by replacing RazorEngine with RazorLight.

When compiling a template, I get the following error:

RazorLight.Compilation.TemplateCompilationException : Failed to compile generated Razor template:
- (24:66) 'GeneratedTemplate.ExecuteAsync()': no suitable method found to override
- (26:12) The name 'WriteLiteral' does not exist in the current context
- (6:2) The name 'Write' does not exist in the current context
- (6:8) The name 'Model' does not exist in the current context
- (34:12) The name 'WriteLiteral' does not exist in the current context

I can't provide a minimal solution since it's all intertwined with a proprietary code base. I'm looking for some explanation of what these errors mean and what could cause them.

doxxx commented

Of course, 5 minutes later, I had an idea of something to try and it worked.

In my test, I was using a template with a structure copied from another project which used my proprietary templating system. The previous system required the following declared at the top of the template file:

@using Synaptive.Axon.Templating
@inherits TemplateBase<TemplateRenderingTests.TemplateModel>

Removing those two lines fixed the problem and the template rendered correctly, including model property references. So now I have to figure out why that pattern was necessary in the old system and whether I still need to do something similar for RazorLight.

doxxx commented

I had to alter my TemplateBase class (as referenced in the template above) to inherit from RazorLight's TemplatePage.

Thanks for sharing. I love when people offer these hints as to what went wrong, especially when they comment on dead issues (vs. commenting on closed issues and not offering anything of value).

Stepping on my soap box:
I highly doubt "proprietary templating system" is really valuable. Someone even literally took advantage of RazorLight's generous licensing terms and renamed the project as their own as part of their consulting arrangement, and basically took full credit for it. I suspect that is what most "proprietary templating systems" are. I've been around the block enough times as a consultant to know these are not valuable things from an IP perspective. No person hired by a VC or PE firm to do due diligence is going to come in and say this, "templating system is why we are buying the company", or that it is any part of a systematic edge over competitors. Is it clean code in that it is strongly typed and relatively easy to maintain? Yes. Intellectual property? NO.

I'm not saying this to put you or your company down, just saying reality is what it is.

@doxxx Your migration path sounds very similar to my own. I also had a need to upgrade a project using RazorEngine to support .NET 6 when I came across RazorLight.

The project also had a custom template class necessitated by RazorEngine:
@inherits CustomHtmlTemplateBase<MyModel>

When upgrading to RazorLight I was able to get rid of the custom class altogether and just refer to the built in TemplatePage class:
@inherits TemplatePage<MyModel>

Thanks for sharing. Hopefully this will benefit someone trying to accomplish the same in the future.

doxxx commented

"Proprietary templating system" was just a convenient shorthand for "closed source code base which makes use of templating so I can't just cut & paste my code to show you the problem". I am not simply wrapping RazorLight to re-sell.

For more context, it's a web server framework with object remoting over WebSockets, templating, and the rest of the kitchen sink, developed internally many years ago, which all of our applications depend on. If we want to make progress towards .NET 6, we need to port this framework so as to avoid rewriting all of our applications to use something else.

@czielin My project needs a custom template page base class because it adds some methods and properties for pages to use (e.g. dependency injection, HTTP context). That may be a bad way of doing things, but as an existing framework, other projects depend on the feature set it provides, so I can't just change it.

Ultimately, my goal is to get applications using Blazor where appropriate, but to get there they first need to work on .NET 6 with the existing frameworks.