Welcome Guest! To enable all features please Login or Register.



Tests using razorlight fail
#1 Posted : Monday, April 6, 2020 11:33:10 PM(UTC)
Rank: Newbie

Groups: Registered
Joined: 5/31/2018(UTC)
Posts: 9
Location: New Zealand

Thanks: 3 times
Was thanked: 4 time(s) in 3 post(s)
Hi all.

We use Razorlight (via FluentEmail) to generate emails (strings) from cshtml files (razor templates).

After upgrading from .netcore 2.2 to 3.1 the code works and tests work through `dotnet test`, but fail when run under ncrunch.

I've made a small reproduction here:

You can run it, navigate to https://localhost:5001/weatherforecast and you'll end up at some plain text html with "Heading: ExpectedString".
You can also run `dotnet test` in the solution folder and the test will pass.
But when run under ncrunch you end up with

fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
RazorLight.Compilation.TemplateCompilationException: Failed to compile generated Razor template:
- (3:35) The type 'Attribute' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
- (3:63) Predefined type 'System.String' is not defined or imported
.... lots more ....

Razorlight needs these new options set in the csproj, maybe ncrunch isn't respecting them?


#2 Posted : Tuesday, April 7, 2020 6:16:29 AM(UTC)
Rank: NCrunch Developer

Groups: Administrators
Joined: 4/16/2011(UTC)
Posts: 6,201

Thanks: 807 times
Was thanked: 1065 time(s) in 1012 post(s)
Hi Dave,

Thanks for sharing this issue and for taking the time to create a sample solution that reproduces it. I've spent today pulling apart the projects involved (Razorlight, FluentEmail, etc) to understand what is happening here and what can be done about it.

The results of this have not been particularly encouraging.

Razorlight makes a call to the DependencyContext of the top-level project (i.e. your test project) to obtain a list of all compile-time references used in the environment from the .deps file. It then uses this as input to the roslyn compiler to compile the views that get handed downstream. This is problematic for NCrunch because the manner in which we build projects is very different to that of a foreground VS build, and we simply don't have the same dependency data available. Consequently the razor compile action fails because it cannot find compile-only references (such as System.Runtime).

In theory, it's possible for us to solve this problem in NCrunch by sifting the raw .deps and propagating compile-time information upwards through the structure. We already do this for runtime references, as otherwise the runtime loader won't let us build a test environment. However, it's taken months of excruciating work to get the dependency structure in a state where the runtime loader can reliably roll with it ... then months more when .NET Core 3 was released and the whole thing moved underneath us again. I presently see no way we can resolve this issue in NCrunch without massive investment of time and a huge risk of breaking the whole system for a good number of users .. which we definitely do not want to do at a time of global crisis.

So in summary, we cannot support this use case.

However, there is an opportunity for a workaround. Razorlight provides you the ability to specify the compile-time references manually through the RazorLightEngineBuilder.AddMetadataReferences method. Unfortunately, all ability to manipulate this is controlled by the FluentEmail library, so you'll need to break out your own class implementing FluentEmail.Razor.ITemplateRenderer that can specify the required references to RazorLightEngineBuilder. If you pass it the references needed to compile the templates, in theory you should be able to use NCrunch with these libraries under .NET Core 3.1.
1 user thanked Remco for this useful post.
davetorutek on 4/7/2020(UTC)
#3 Posted : Tuesday, April 7, 2020 10:29:18 PM(UTC)
Rank: Newbie

Groups: Registered
Joined: 5/31/2018(UTC)
Posts: 9
Location: New Zealand

Thanks: 3 times
Was thanked: 4 time(s) in 3 post(s)
Thanks for the reply, we'll implement a work around on our side.

For anyone else that stumbles upon this, heres a start on what you need:


        internal static FluentEmailServicesBuilder AddHackedRazorRenderer(this FluentEmailServicesBuilder builder)
            builder.Services.TryAdd(ServiceDescriptor.Singleton<ITemplateRenderer, RazorRenderer>(sp =>
                var renderer = new RazorRenderer();

                var engineField = typeof(RazorRenderer).GetField("_engine", BindingFlags.Instance | BindingFlags.NonPublic);
                    new RazorLightEngineBuilder()
                            MetadataReference.CreateFromFile(typeof(System.Object).Assembly.Location.Replace("System.Private.CoreLib.dll", "System.Runtime.dll")),
                            MetadataReference.CreateFromFile(typeof(System.Object).Assembly.Location.Replace("System.Private.CoreLib.dll", "System.Collections.dll"))

                return renderer;

            return builder;
2 users thanked davetorutek for this useful post.
Remco on 4/8/2020(UTC), mkoertgen on 5/9/2020(UTC)
Users browsing this topic
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

YAF | YAF © 2003-2011, Yet Another Forum.NET
This page was generated in 0.206 seconds.