Search code examples
c#.net.net-4.8.net-8.0microsoft.codeanalysis

Using RazorEngineCore Library getting error Could not load file or assembly 'Microsoft.CodeAnalysis Version=4.7.0.0,PublicKeyToken=31bf3856ad364e35'


I have an ASP.NET Website project. It's package.config

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.Bcl.AsyncInterfaces" version="8.0.0" targetFramework="net48" />
  <package id="Microsoft.CodeAnalysis.NetAnalyzers" version="8.0.0" targetFramework="net48" developmentDependency="true" />
  <package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.WebSites" version="4.1.0" targetFramework="net48" />
  <package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="4.1.0" targetFramework="net48" />
</packages>

Then Web.config looks like, just pasting the runtime binding section related to CodeAnalysis,

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.CodeAnalysis" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.7.0.0" newVersion="4.7.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.CodeAnalysis.CSharp" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.7.0.0" newVersion="4.7.0.0" />
      </dependentAssembly>
   </assemblyBinding>
</runtime>

Then I have a shared library project which uses RazorEngineCore library. This is how the decompiled RazorEngine class looks,

#region Assembly RazorEngineCore, Version=2023.11.2.0, Culture=neutral, PublicKeyToken=c32700229a1808ba
// C:\Code\baseline\globalpackages\razorenginecore\2023.11.2\lib\net6.0\RazorEngineCore.dll
// Decompiled with ICSharpCode.Decompiler 8.1.1.7464
#endregion

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;

namespace RazorEngineCore;

public class RazorEngine : IRazorEngine
{
    public IRazorEngineCompiledTemplate<T> Compile<T>(string content, Action<IRazorEngineCompilationOptionsBuilder> builderAction = null, CancellationToken cancellationToken = default(CancellationToken)) where T : IRazorEngineTemplate
    {
        IRazorEngineCompilationOptionsBuilder razorEngineCompilationOptionsBuilder = new RazorEngineCompilationOptionsBuilder();
        razorEngineCompilationOptionsBuilder.AddAssemblyReference(typeof(T).Assembly);
        razorEngineCompilationOptionsBuilder.Inherits(typeof(T));
        builderAction?.Invoke(razorEngineCompilationOptionsBuilder);
        return new RazorEngineCompiledTemplate<T>(CreateAndCompileToStream(content, razorEngineCompilationOptionsBuilder.Options, cancellationToken));
    }

    public Task<IRazorEngineCompiledTemplate<T>> CompileAsync<T>(string content, Action<IRazorEngineCompilationOptionsBuilder> builderAction = null, CancellationToken cancellationToken = default(CancellationToken)) where T : IRazorEngineTemplate
    {
        return Task.Factory.StartNew(() => Compile<T>(content, builderAction, cancellationToken));
    }

    public IRazorEngineCompiledTemplate Compile(string content, Action<IRazorEngineCompilationOptionsBuilder> builderAction = null, CancellationToken cancellationToken = default(CancellationToken))
    {
        IRazorEngineCompilationOptionsBuilder razorEngineCompilationOptionsBuilder = new RazorEngineCompilationOptionsBuilder();
        razorEngineCompilationOptionsBuilder.Inherits(typeof(RazorEngineTemplateBase));
        builderAction?.Invoke(razorEngineCompilationOptionsBuilder);
        return new RazorEngineCompiledTemplate(CreateAndCompileToStream(content, razorEngineCompilationOptionsBuilder.Options, cancellationToken));
    }

    public Task<IRazorEngineCompiledTemplate> CompileAsync(string content, Action<IRazorEngineCompilationOptionsBuilder> builderAction = null, CancellationToken cancellationToken = default(CancellationToken))
    {
        return Task.Factory.StartNew(() => Compile(content, builderAction, cancellationToken));
    }

    protected unsafe virtual RazorEngineCompiledTemplateMeta CreateAndCompileToStream(string templateSource, RazorEngineCompilationOptions options, CancellationToken cancellationToken)
    {
        templateSource = WriteDirectives(templateSource, options);
        string rootDirectoryPath = ".";
        string text = (string.IsNullOrWhiteSpace(options.TemplateFilename) ? (Path.GetRandomFileName() + ".cshtml") : options.TemplateFilename);
        RazorProjectEngine razorProjectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, RazorProjectFileSystem.Create(rootDirectoryPath), delegate (RazorProjectEngineBuilder builder)
        {
            builder.SetNamespace(options.TemplateNamespace);
        });
        RazorSourceDocument source = RazorSourceDocument.Create(templateSource, text);
        RazorCSharpDocument cSharpDocument = razorProjectEngine.Process(source, null, new List<RazorSourceDocument>(), new List<TagHelperDescriptor>()).GetCSharpDocument();
        SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(cSharpDocument.GeneratedCode, null, "", null, cancellationToken);
        CSharpCompilation cSharpCompilation = CSharpCompilation.Create(text, new SyntaxTree[1] { syntaxTree }, options.ReferencedAssemblies.Select(delegate (Assembly ass)
        {
            ass.TryGetRawMetadata(out var blob, out var length);
            return AssemblyMetadata.Create(ModuleMetadata.CreateFromMetadata((IntPtr)blob, length)).GetReference();
        }).Concat(options.MetadataReferences).ToList(), new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
        MemoryStream memoryStream = new MemoryStream();
        MemoryStream memoryStream2 = (options.IncludeDebuggingInfo ? new MemoryStream() : null);
        EmitResult emitResult = cSharpCompilation.Emit(memoryStream, memoryStream2, null, null, null, null, null, null, null, null, cancellationToken);
        if (!emitResult.Success)
        {
            throw new RazorEngineCompilationException
            {
                Errors = emitResult.Diagnostics.ToList(),
                GeneratedCode = cSharpDocument.GeneratedCode
            };
        }

        return new RazorEngineCompiledTemplateMeta
        {
            AssemblyByteCode = memoryStream.ToArray(),
            PdbByteCode = memoryStream2?.ToArray(),
            GeneratedSourceCode = (options.IncludeDebuggingInfo ? cSharpDocument.GeneratedCode : null),
            TemplateSource = (options.IncludeDebuggingInfo ? templateSource : null),
            TemplateNamespace = options.TemplateNamespace,
            TemplateFileName = text
        };
    }

    protected virtual string WriteDirectives(string content, RazorEngineCompilationOptions options)
    {
        StringBuilder stringBuilder = new StringBuilder();
        StringBuilder stringBuilder2 = stringBuilder;
        StringBuilder stringBuilder3 = stringBuilder2;
        StringBuilder.AppendInterpolatedStringHandler handler = new StringBuilder.AppendInterpolatedStringHandler(10, 1, stringBuilder2);
        handler.AppendLiteral("@inherits ");
        handler.AppendFormatted(options.Inherits);
        stringBuilder3.AppendLine(ref handler);
        foreach (string defaultUsing in options.DefaultUsings)
        {
            stringBuilder2 = stringBuilder;
            StringBuilder stringBuilder4 = stringBuilder2;
            handler = new StringBuilder.AppendInterpolatedStringHandler(7, 1, stringBuilder2);
            handler.AppendLiteral("@using ");
            handler.AppendFormatted(defaultUsing);
            stringBuilder4.AppendLine(ref handler);
        }

        stringBuilder.Append(content);
        return stringBuilder.ToString();
    }
}
#if false // Decompilation log
'218' items in cache
------------------
Resolve: 'System.Runtime, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Found single assembly: 'System.Runtime, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Load from: 'C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\6.0.26\ref\net6.0\System.Runtime.dll'
------------------
Resolve: 'System.Linq.Expressions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Found single assembly: 'System.Linq.Expressions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Load from: 'C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\6.0.26\ref\net6.0\System.Linq.Expressions.dll'
------------------
Resolve: 'System.Collections, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Found single assembly: 'System.Collections, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Load from: 'C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\6.0.26\ref\net6.0\System.Collections.dll'
------------------
Resolve: 'Microsoft.CodeAnalysis, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
Found single assembly: 'Microsoft.CodeAnalysis, Version=4.8.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
WARN: Version mismatch. Expected: '4.0.0.0', Got: '4.8.0.0'
Load from: 'C:\Code\baseline\globalpackages\microsoft.codeanalysis.common\4.8.0\lib\net6.0\Microsoft.CodeAnalysis.dll'
------------------
Resolve: 'Microsoft.AspNetCore.Razor.Language, Version=6.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'
Found single assembly: 'Microsoft.AspNetCore.Razor.Language, Version=6.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'
Load from: 'C:\Code\baseline\globalpackages\microsoft.aspnetcore.razor.language\6.0.1\lib\netstandard2.0\Microsoft.AspNetCore.Razor.Language.dll'
------------------
Resolve: 'System.Collections.Immutable, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Found single assembly: 'System.Collections.Immutable, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
WARN: Version mismatch. Expected: '6.0.0.0', Got: '7.0.0.0'
Load from: 'C:\Code\baseline\globalpackages\system.collections.immutable\7.0.0\lib\net6.0\System.Collections.Immutable.dll'
------------------
Resolve: 'System.Linq, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Found single assembly: 'System.Linq, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Load from: 'C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\6.0.26\ref\net6.0\System.Linq.dll'
------------------
Resolve: 'Microsoft.CodeAnalysis.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
Found single assembly: 'Microsoft.CodeAnalysis.CSharp, Version=4.8.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
WARN: Version mismatch. Expected: '4.0.0.0', Got: '4.8.0.0'
Load from: 'C:\Code\baseline\globalpackages\microsoft.codeanalysis.csharp\4.8.0\lib\net6.0\Microsoft.CodeAnalysis.CSharp.dll'
------------------
Resolve: 'System.Runtime.InteropServices.RuntimeInformation, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Found single assembly: 'System.Runtime.InteropServices.RuntimeInformation, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Load from: 'C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\6.0.26\ref\net6.0\System.Runtime.InteropServices.RuntimeInformation.dll'
------------------
Resolve: 'System.Runtime.Loader, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Found single assembly: 'System.Runtime.Loader, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Load from: 'C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\6.0.26\ref\net6.0\System.Runtime.Loader.dll'
------------------
Resolve: 'System.Runtime.InteropServices, Version=6.0.0.0, Culture=neutral, PublicKeyToken=null'
Found single assembly: 'System.Runtime.InteropServices, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Load from: 'C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\6.0.26\ref\net6.0\System.Runtime.InteropServices.dll'
------------------
Resolve: 'System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=null'
Found single assembly: 'System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Load from: 'C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\6.0.26\ref\net6.0\System.Runtime.CompilerServices.Unsafe.dll'
#endif

I am getting this exception in my shared library project when I run the website. Got the following exception.

Error=Could not load file or assembly 'Microsoft.CodeAnalysis, Version=4.7.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

This is how my shared library project .csporj file looks like,

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

  <PropertyGroup>
    <TargetFrameworks>net48;net6.0</TargetFrameworks>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
    <Company>--</Company>
    <Authors>--</Authors>
    <LangVersion>8.0</LangVersion>
    <Nullable>disable</Nullable>
    <WarningsAsErrors>Nullable</WarningsAsErrors>
    <EnableNETAnalyzers>true</EnableNETAnalyzers>
    <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
    <AnalysisLevel>latest</AnalysisLevel>
  </PropertyGroup>

  <Target Name="GetTargetPath" Returns="@(_FakeOutputPath)">
    <ItemGroup Condition="'$(OutputType)' == 'Library'">
      <_FakeOutputPath Include="$(MSBuildProjectDirectory)\$(OutputPath)\$(_InstallerTargetFramework)\$(AssemblyName).dll" />
    </ItemGroup>
  </Target>

  <PropertyGroup Condition="'$(TF_BUILD)' == 'true' Or '$(GITHUB_ACTIONS)' == 'true'">
    <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
    <PackageReference Include="Antlr4.Runtime.Standard" />
    <PackageReference Include="AutoMapper" />
    <PackageReference Include="Dapper.Contrib" />
    <PackageReference Include="Microsoft.Data.SqlClient" />
    <PackageReference Include="Microsoft.Extensions.Http" />
    <PackageReference Include="MiniProfiler.Minimal" />
    <PackageReference Include="Newtonsoft.Json" />
    <PackageReference Include="RazorEngineCore" />
    <PackageReference Include="System.Configuration.ConfigurationManager" />
  </ItemGroup>

  <!--
    Because of compatibility issues with dependencies between NET Standard/Framework versions they are not
    automatically copied to our website project type. And since there's no other way to do this, copy them manually here...
  -->
  <Target Name="CopyDllToWebsite" AfterTargets="AfterBuild" Condition="'$(SolutionName)' == 'Solution' AND '$(TargetFramework)' == 'net48'">
    <Message Text="Copying DLLs from Library to Website" />
    <Exec Command="xcopy /d /s /y /c /i /r /f &quot;$(TargetDir)*&quot; &quot;..\..\..\Solution\application\bin&quot;" />
  </Target>

</Project>

What should be done in order to resolve this Microsoft.CodeAnalysis related exception?

UPDATE: I am getting this error at runtime, project builds fine.


Solution

  • Your binding redirects are wrong. As you can see in your Web.config you have:

     <dependentAssembly>
            <assemblyIdentity name="Microsoft.CodeAnalysis" publicKeyToken="31bf3856ad364e35" culture="neutral" />
            <bindingRedirect oldVersion="0.0.0.0-4.7.0.0" newVersion="4.7.0.0" />
          </dependentAssembly>
    

    Redirect to version 4.7.0.0 but your RazorEngineCore resolves Microsoft.CodeAnalysis the 4.8.0.0 version.

    Generating new binding redirects should fix your issue