Mixing .net Framework projects with .net Core projects (and languages) - System.IO.FileNotFoundException

2

I have a solution in which most of the projects are VB.net projects which all target the .NET Framework 4.8. All of those specific projects compile properly and are running in production.

I have added a C# project that targets .net standard 2.0. The primary reason for this particular project is to create a component that can process razor templates (given a model of course) in order to create output files using the RazorLight_wik8wz nuget package (I don't really care which package I use so long as I can render a razor template in memory because the output generated by the model/template pair may be persisted in different places in different cases).

In theory, and based on my understanding, I should be able to reference and use a .net standard 2.0 library project from my other .net framework 4.8 projects. However, I can't seem to get this to work (even though everything compiles and runs).

I've tried several different packages based on RazorLight--but I get similar results when I try to use them. I'm simply not sure if I'm encountering a bug or if I'm not doing something properly.

The C# project is named "JobOutputGenerator." I have added the nuget package called "RazorLight_wik8wz" and created an object called JobOutput that currently looks like this:

using System.Threading.Tasks;
using RazorLight;

public class JobOutput
{
    public static async Task<byte[]> CreateOutputAsync(string RazorTemplate, object Model)
    {
        RazorLightEngine engine = new RazorLightEngineBuilder().UseMemoryCachingProvider().Build();
        return System.Text.Encoding.ASCII.GetBytes(await engine.CompileRenderAsync(RazorTemplate.GetHashCode().ToString() + Model.GetHashCode().ToString(), RazorTemplate, Model));
    }

}

I have created another project called "TesterApp" which is a VB.NET project that targets .NET Framework 4.8. It is a simple windows form project that references JobOutputGenerator.

I have a button that does the following:

Private Sub btnRenderSample_Click(sender As Object, e As EventArgs) Handles btnRenderSample.Click
    Dim template As String = "Hello @Model.Name"
    Dim Model1 = New With {.Name = "John Doe"}
    Dim bytesTask = JobOutput.CreateOutputAsync(template, Model1)
    Dim str = System.Text.Encoding.ASCII.GetString(bytesTask.Result)
    MsgBox(str)
End Sub

When I launch the TesterApp in debug mode in Visual Studio, all projects compile just fine, and then when I click my sample button, Visual Studio breaks on the line (while highlighted in green):

Dim bytesTask = JobOutput.CreateOutputAsync(template, Model1)

with a box that is titled "Exception Unhandled" that says:

System.IO.FileNotFoundException: 'Could not load file or assembly 'RazorLight, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.'

I have run fuslogvw and TesterApp has no problem locating JobOutputGenerator.dll:

<meta http-equiv="Content-Type" content="charset=unicode-1-1-utf-8"><!-- saved from url=(0015)assemblybinder: --><html><pre>
*** Assembly Binder Log Entry  (6/7/2019 @ 9:37:08 AM) ***

The operation was successful.
Bind result: hr = 0x0. The operation completed successfully.

Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable  X:\Workspaces\SOLUTIONROOTFOLDER\TesterApp\bin\Debug\TesterApp.exe
--- A detailed error log follows. 

=== Pre-bind state information ===
LOG: DisplayName = JobOutputGenerator, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
 (Fully-specified)
LOG: Appbase = file:///X:/Workspaces/SOLUTIONROOTFOLDER/TesterApp/bin/Debug/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = TesterApp.exe
Calling assembly : TesterApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: X:\Workspaces\SOLUTIONROOTFOLDER\TesterApp\bin\Debug\TesterApp.exe.Config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///X:/Workspaces/SOLUTIONROOTFOLDER/TesterApp/bin/Debug/JobOutputGenerator.DLL.
LOG: Assembly download was successful. Attempting setup of file: X:\Workspaces\SOLUTIONROOTFOLDER\TesterApp\bin\Debug\JobOutputGenerator.dll
LOG: Entering run-from-source setup phase.
LOG: Assembly Name is: JobOutputGenerator, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
LOG: Binding succeeds. Returns assembly from X:\Workspaces\SOLUTIONROOTFOLDER\TesterApp\bin\Debug\JobOutputGenerator.dll.
LOG: Assembly is loaded in default load context.

</pre></html>

I did, however, find this little "gem" in fuslogvw and I don't know what to do about it:

*** Assembly Binder Log Entry  (6/7/2019 @ 9:37:09 AM) ***

The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.

Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable  X:\Workspaces\SOLUTIONROOTFOLDER\TesterApp\bin\Debug\TesterApp.exe
--- A detailed error log follows. 

=== Pre-bind state information ===
LOG: DisplayName = RazorLight, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null
 (Fully-specified)
LOG: Appbase = file:///X:/Workspaces/SOLUTIONROOTFOLDER/TesterApp/bin/Debug/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = TesterApp.exe
Calling assembly : JobOutputGenerator, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: X:\Workspaces\SOLUTIONROOTFOLDER\TesterApp\bin\Debug\TesterApp.exe.Config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///X:/Workspaces/SOLUTIONROOTFOLDER/TesterApp/bin/Debug/RazorLight.DLL.
LOG: Attempting download of new URL file:///X:/Workspaces/SOLUTIONROOTFOLDER/TesterApp/bin/Debug/RazorLight/RazorLight.DLL.
LOG: Attempting download of new URL file:///X:/Workspaces/SOLUTIONROOTFOLDER/TesterApp/bin/Debug/RazorLight.EXE.
LOG: Attempting download of new URL file:///X:/Workspaces/SOLUTIONROOTFOLDER/TesterApp/bin/Debug/RazorLight/RazorLight.EXE.
LOG: All probing URLs attempted and failed.

The following is the contents of the JobOutputGenerator.csproj:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup Label="Globals">
    <SccProjectName>SAK</SccProjectName>
    <SccProvider>SAK</SccProvider>
    <SccAuxPath>SAK</SccAuxPath>
    <SccLocalPath>SAK</SccLocalPath>
  </PropertyGroup>

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

  <PropertyGroup>
    <RestoreProjectStyle>PackageReference</RestoreProjectStyle>
    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
  </PropertyGroup>


  <ItemGroup>
    <PackageReference Include="ILRepack.MSBuild.Task" Version="2.0.1" />
    <PackageReference Include="RazorLight_wik8wz" Version="2.0.0" />
  </ItemGroup>

      <Target Name="ILRepack" AfterTargets="Build">

        <PropertyGroup>
            <WorkingDirectory>$(MSBuildThisFileDirectory)bin\$(Configuration)\$(TargetFramework)</WorkingDirectory>
        </PropertyGroup>

        <ILRepack 
            OutputType="$(OutputType)" 
            MainAssembly="$(AssemblyName).dll" 
            OutputAssembly="$(AssemblyName).dll" 
            InputAssemblies="$(WorkingDirectory)\*.dll" 
            WilcardInputAssemblies="true"
            WorkingDirectory="$(WorkingDirectory)" />
    </Target>
</Project>
c#
vb.net
.net-standard-2.0
.net-core-2.2
.net-4.7.1
asked on Stack Overflow Jun 6, 2019 by Dimitri Rodis • edited Jun 7, 2019 by Dimitri Rodis

1 Answer

2

So after more searches I came across the following problem and set of posts. Following this workaround seems to have solved my problem for now.

Apparently this has been a problem for quite some time (since 2017--thanks Microsoft!) without a permanent fix.

The problem was first reported here:

NuGet dependencies of .NET Standard library referenced from classic .NET app cannot be resolved at runtime with FileNotFoundException #1582

If you read through this string of messages, you eventually come to this workaround near the bottom, with others confirming this person's findings. Following this workaround causes the DLL files to all get built/copied to the Debug folder and now the referenced DLL is no longer "missing" and the exception I was receiving at runtime is gone.

I made this modification to my JobOutputGenerator .csproj file, except that I used ;net48 instead of ;net461 .

NOTE THE TAG:

<TargetFramework>

needs to change to (note the "s")

<TargetFrameworks>

in order for this to work--otherwise your project won't load properly in Visual Studio.

answered on Stack Overflow Jun 7, 2019 by Dimitri Rodis

User contributions licensed under CC BY-SA 3.0