question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Type resolution depends on the program that is running, not the assembly being processed.

See original GitHub issue

An assembly built to target the .Net Framework expects to resolve system references in the GAC; however a .net (core) program using Cecil to manipulate that assembly resolves them to the trusted locations under dotnet/shared. The two files will not always match up.

Here’s an example – ClassLibrary.csproj builds a WPF-consuming assembly that references WindowsBase.dll v4.0.0.0 in the GAC. CecilGAC.csproj is a simple .net6.0 program that reads and rewrites the ClassLibrary1.dll assembly.

CecilGAC.zip

The program fails during write with

Mono.Cecil.ResolutionException: Failed to resolve System.Windows.Threading.DispatcherPriority
at Mono.Cecil.Mixin.CheckedResolve(TypeReference self)
...

because a WindowsBase.dll v4.0.0.0 has been found within C:\Program Files\dotnet\shared\Microsoft.NETCore.App; but that assembly is a stub containing only

internal class <Module>
{
}

However, if CecilGAC.csproj is modified to be

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net48</TargetFramework>
  </PropertyGroup>
  
  <ItemGroup>
    <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies.net48" Version="1.0.2">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Mono.Cecil" Version="0.11.4" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\ClassLibrary1\ClassLibrary1.csproj" />
  </ItemGroup>

</Project>

building against .Net Framework v4.8, the write operation finds the expected file in the GAC, and the type resolution completes successfully.

Because a suitable strong-named assembly has been found in the ,net core case, a simple reactive approach such as overriding the AssemblyResolver to handle resolution failures by checking the GAC (if present) does not resolve the issue; the necessary fix would be to replace the #if NET_CORE compile-time logic with a runtime selection based on the [TargetFramework] attribute value of the assembly being manipulated.

[ADDED] An alternative would be to recognise such a pure stub assembly and consider it an assembly resolution failure; this form of stub seems to be a standard pattern for GUI-related assemblies.

Issue Analytics

  • State:open
  • Created a year ago
  • Reactions:1
  • Comments:7 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
SteveGilhamcommented, Jun 28, 2022

You can get the attribute type name and examine the associated binary blob data w/o any resolver as the following example demonstrates

using System;
using System.IO;
using System.Linq;
using System.Reflection;

using Mono.Cecil;

namespace CecilGAC
{
  public class NonResolver : IAssemblyResolver
  {
    public AssemblyDefinition Resolve(AssemblyNameReference name)
    {
      throw new NotImplementedException();
    }

    public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
    {
      throw new NotImplementedException();
    }

    public void Dispose()
    {
    }
  }

  internal class Program
  {
    private static void Main(string[] args)
    {
      var parameters = new ReaderParameters();
      parameters.AssemblyResolver = new NonResolver();

      var def = AssemblyDefinition.ReadAssembly([assembly path goes here], parameters);
      foreach (var a in def.CustomAttributes)
      {
        Console.WriteLine(a.AttributeType.FullName);
        var b = a.GetBlob();
        var s = System.Text.Encoding.ASCII.GetString(b);
        Console.WriteLine(s);
      }
    }
  }
}
0reactions
Zastaicommented, Jun 27, 2022

Is there no chicken/egg issue with trying to have the behaviour of the resolver depend on [TargetFramework]? For one thing, I would expect it would need to resolve TargetFrameworkAttribute before being able to look at the target framework value.

Read more comments on GitHub >

github_iconTop Results From Across the Web

MSB3277: Found conflicts between different versions of ' ...
This error occurs during a build when more than one version of the same dependent assembly is referenced in a build of the...
Read more >
The located assembly's manifest definition does not match ...
This assembly does not match what was requested and therefore you get this error. In simple words, it can't find the assembly that...
Read more >
How the Runtime Locates Assemblies - .NET Framework
The runtime uses the same resolution process regardless of whether the reference is for a static or dynamic assembly.
Read more >
Name resolution (programming languages)
In programming languages, name resolution is the resolution of the tokens within program expressions to the intended program components.
Read more >
Drafting Resolutions | United Nations
Key to successful drafting of resolutions​​ This process will often ensure the draft's acceptance when it is put to the committee for decision....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found