Razorlight: ArgumentNullException when performing AspNetCore Integration Tests using `Microsoft.AspNetCore.TestHost.TestServer`

Created on 28 Jun 2018  路  9Comments  路  Source: toddams/RazorLight

Describe the bug
ArgumentNullException when performing AspNetCore Integration Tests using Microsoft.AspNetCore.TestHost.TestServer

Value cannot be null.
Parameter name: operatingAssembly (See inner exception for details.) ---> 
System.ArgumentNullException: Value cannot be null.
Parameter name: operatingAssembly
   
at RazorLight.Compilation.RoslynCompilationService..ctor(IMetadataReferenceManager referenceManager, Assembly operatingAssembly)
   
at RazorLight.RazorLightEngineBuilder.Build()
   
at Services.Contract.IoC.ContractDomainModule.<>c.<Load>b__0_0(IComponentContext x)
   

To reproduce:
Run a test class library targeting .NET Framework 4.7.1. but running a .NETCore api. Inject the RazorlightEngine in a controller, query the controller end point and wait for it to throw.

Information (please complete the following information):

  • OS: Windows 10
  • Platform .NET Framework 4.x
  • RazorLight version: 2.0.0-beta1
Investigate

Most helpful comment

Just pitfall after pitfall. Absolutely brutal.

All 9 comments

I'm getting the same exception in a .NET Framework 4.6.1 MSTest project -- but not when I'm running the ASP.NET Core project...

operatingAssembly must be null from a test project?

+1

Too many problems with this project. I finally must give up.

Just pitfall after pitfall. Absolutely brutal.

Having the same issue, trying to unit test my code.

you can get a step closer by on your engine builder adding .SetOperatingAssembly(Assembly assembly) however this will still error but with a different error message regarding DependencyContext.

I have a .netframework project and I had a similar issue. You need to call "SetOperatingAssembly" and pass the assembly where you actually use the razor engine. To make this work I created a factory that is easily injectable and it can create the razor engine wherever and whenever I need it.
Example of the factory:

public class RazorEngineFactory : IRazorEngineFactory
{
    public IRazorLightEngine Create()
    {
        return new RazorLightEngineBuilder()
            .SetOperatingAssembly(Assembly.GetCallingAssembly())
            .UseFileSystemProject(Directory.GetCurrentDirectory())
            .UseMemoryCachingProvider()
            .Build();
    }
}

Just inject this factory and use it to create the razor engine instead of directly injecting the engine.
By the way, i am using the filesystem resource type, just change it to embedded as you need.

@BarsikV Thanks. Please update the README.md via PR. Very easy to do and doesn't require cloning the git repo locally.

That said, as a code/peer review, perhaps Create() should take a parameter to avoid JIT in-line optimization changing the calling assembly value:

c# public class RazorEngineFactory : IRazorEngineFactory { public IRazorLightEngine Create(Assembly operatingAssembly = null) { return new RazorLightEngineBuilder() .SetOperatingAssembly(operatingAssembly ?? Assembly.GetCallingAssembly()) .UseFileSystemProject(Directory.GetCurrentDirectory()) .UseMemoryCachingProvider() .Build(); } }

you can then call razorEngineFactory.Create(this.GetType().Assembly)) which will be invariant under all optimizations.

I ended up implementing the interface from https://github.com/toddams/RazorLight/issues/202#issuecomment-607912964 as RazorLightEngineWithFileSystemProjectFactory.

It is a somewhat superfluous interface, but most people are probably calling RazorLight with a file system, so it makes sense to give them something standard to hook into. It also frankly will make reading tests easier.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

AdrianPell picture AdrianPell  路  4Comments

xxeasterxx picture xxeasterxx  路  5Comments

shobman picture shobman  路  4Comments

IInvocation picture IInvocation  路  6Comments

Hubert-Rybak picture Hubert-Rybak  路  5Comments