Skip to content

Conversation

@sonyps5201314
Copy link

@sonyps5201314 sonyps5201314 commented Oct 11, 2025

When decompiling the JsonSchemaMapper.JsonSchemaMapper.MapJsonSchemaCore function in "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\Microsoft.VisualStudio.Copilot.Contracts\Microsoft.VisualStudio.Copilot.dll" on a machine with DotNet SDK 3.1 installed, the following error occurs:
image
Because ilspy loads System.Text.Json.dll in "C:\Program Files\dotnet\shared\Microsoft.NETCore.App\3.1.32\", but its version is too old, so it does not match, resulting in the error in the screenshot.
Applying this PR will fix this issue.

}
catch (Exception ex)
{
Trace.TraceWarning(ex.ToString());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swallowing exceptions is not allowed.

@siegfriedpammer
Copy link
Member

siegfriedpammer commented Oct 11, 2025

I don't think that this is an appropriate fix.

The problem is that the library lives in an isolated folder without all the references and that it targets .NETStandard,Version=2.0. The System.Text.Json reference that is not correctly resolved is actually package-provided.

With your change ILSpy would load an assembly with version 5.0.0.0 from .NET 5.0, an assembly with version 8.0.0.0 from .NET 8.0 and so on and so forth. I am not convinced that this is the right approach, it will just mix assemblies from different framework versions which are not compatible at all.

The best ILSpy can do without resorting to "magic" is use the assemblies located in the same folder or in folders provided via .deps.json, both of which are missing in this case, because the referenced assemblies are part of the Visual Studio distribution and are located somewhere else.

This is something that needs to be fixed by user intervention and ILSpy will always honor the assemblies it finds in the assembly list: the user needs to manually pick the correct assemblies and load them beforehand because ILSpy cannot and never will be able to detect whether an assembly is part of the framework or provided via a nuget package without additional information.

@sonyps5201314
Copy link
Author

sonyps5201314 commented Oct 13, 2025

You are right. It may indeed lead to the introduction of dlls of different .NET versions into a project, but it can at least alleviate the compilation error problem for now. I have tried the method you mentioned of loading "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\PublicAssemblies\System.Text.Json.dll" into the assembly list first, but it did not work as we expected, because the code

				string? file = parent.GetUniversalResolver(applyWinRTProjections).FindAssemblyFile(reference);

				if (file != null)
				{
					// Load assembly from disk
					LoadedAssembly? asm;
					if (loadOnDemand)
					{
						asm = assemblyList.OpenAssembly(file, isAutoLoaded: true);
					}
					else
					{
						asm = assemblyList.FindAssembly(file);
					}
					if (asm != null)
					{
						referenceLoadInfo.AddMessage(reference.FullName, MessageKind.Info, "Success - Loading from: " + file);
						return await asm.GetMetadataFileOrNullAsync().ConfigureAwait(false);
					}
					return null;
				}
				else
				{
					// Assembly not found; try to find a similar-enough already-loaded assembly
					module = await alreadyLoadedAssemblies.TryGetSimilarModuleAsync(reference).ConfigureAwait(false);
					if (module == null)
					{
						referenceLoadInfo.AddMessageOnce(reference.FullName, MessageKind.Error, "Could not find reference: " + reference.FullName);
					}
					else
					{
						referenceLoadInfo.AddMessageOnce(reference.FullName, MessageKind.Info, "Success - Found in Assembly List with different TFM or version: " + module.FileName);
					}
					return module;
				}

restricts ilspy to search for the dll in the user system (C:\Program Files\dotnet) first. If it is not found, it will use the dll in the "assembly list", unless I comment out case TargetFrameworkIdentifier.NETStandard: in the following code

		public string? FindAssemblyFile(IAssemblyReference name)
		{
			if (name.IsWindowsRuntime)
			{
				return FindWindowsMetadataFile(name);
			}

			string? file;
			switch (targetFrameworkIdentifier)
			{
				case TargetFrameworkIdentifier.NET:
				case TargetFrameworkIdentifier.NETCoreApp:
				//case TargetFrameworkIdentifier.NETStandard:
					if (IsZeroOrAllOnes(targetFrameworkVersion))
						goto default;
					file = dotNetCorePathFinder.Value.TryResolveDotNetCore(name);
					if (file != null)
						return file;
					goto default;
				case TargetFrameworkIdentifier.Silverlight:
					if (IsZeroOrAllOnes(targetFrameworkVersion))
						goto default;
					file = ResolveSilverlight(name, targetFrameworkVersion);
					if (file != null)
						return file;
					goto default;
				default:
					return ResolveInternal(name);
			}
		}

Perhaps adding an entry in the File menu to allow users to set the target framework of the dll of type TargetFrameworkIdentifier.NETStandard would be a better solution, rather than defaulting it to dotnet core. For example, as shown below:

NETStandard Target Runtime
	.Net Core
			(version by scan user C:\Program Files\dotnet direcroty)
			3.1.32
			6.0.36
			8.0.20
			9.0.9
			10.0.0-rc.1.25451.107
	.Net Framework

Or just delete the line case TargetFrameworkIdentifier.NETStandard: from the FindAssemblyFile function as I did above.

@sonyps5201314
Copy link
Author

I found that dotPeek does not have this problem, and it provides many practical functions, as shown below:
image
image
This issue can be temporarily resolved by the following two related commits (not perfect, the icon does not update after loading the missing dll reference midway)
sonyps5201314@54d2e80
#3013
I also found that ilspy does not support record with statement, but dotPeek does not have this problem:
image
image

@sonyps5201314
Copy link
Author

sonyps5201314 commented Oct 13, 2025

In addition, I think Ilspy should use all managed DLLs of Visual Studio as a test case for release. If it can perfectly decompile all managed DLLs of vs without user intervention, and can make the generated VS project perfectly compiled back to exe/dll in one go, then it can be considered a new version to be released. After all, VS is a large .NET software and its use of .NET syntax will be more comprehensive.

@siegfriedpammer
Copy link
Member

Good idea 👍 contributions welcome anytime 🙏

@siegfriedpammer
Copy link
Member

I also found that ilspy does not support record with statement, but dotPeek does not have this problem:

but we have tests for with expressions that just work fine:

public class WithExpressionTests
{
public Fields Test(Fields input)
{
return input with {
A = 42,
B = 3.141,
C = input
};
}
public Fields Test2(Fields input)
{
return input with {
A = 42,
B = 3.141,
C = input with {
A = 43
}
};
}
}
}

Can you please create a separate issue with a reproducer? Thanks!

@siegfriedpammer
Copy link
Member

I found that dotPeek does not have this problem, and it provides many practical functions, as shown below:

ILSpy has most of these too:

"Manage assembly lists"

grafik grafik grafik

Search:

grafik

We originally had planned a filter box above the tree view, but it never got implemented and nobody has asked for it in 14 years.

@sonyps5201314
Copy link
Author

sonyps5201314 commented Oct 13, 2025

ILSpy has most of these too:

"Manage assembly lists"

grafik grafik grafik

Importing and exporting assembly lists is not supported, There's no "Open from Running Process" feature, but dnspy ​​does. However, I don't have time to copy this feature to ilspy, so I developed a copy-paste assembly list to share the assembly list between ilspy and dnspy. However, my AI writing is relatively rough, so I don't believe the official will accept these PRs, so I didn't submit them:
sonyps5201314/dnSpy@4e03bb3
a0a2a50

Search:

grafik We originally had planned a filter box above the tree view, but it never got implemented and nobody has asked for it in 14 years.

My apologies, I didn't notice that the search box on the right supports searching by Assembly name when Assembly is selected as the search type, because it isn't the default type. Perhaps adding an "Everything" option and making it the default would improve the UI's usability. This would also be more in line with modern trends, similar to the CTRL+T feature in Visual Studio and the Jump anywhere function in IDA 9.2.

@sonyps5201314
Copy link
Author

I also found that ilspy does not support record with statement, but dotPeek does not have this problem:

but we have tests for with expressions that just work fine:

public class WithExpressionTests
{
public Fields Test(Fields input)
{
return input with {
A = 42,
B = 3.141,
C = input
};
}
public Fields Test2(Fields input)
{
return input with {
A = 42,
B = 3.141,
C = input with {
A = 43
}
};
}
}
}

Can you please create a separate issue with a reproducer? Thanks!

#3593
I spent a few hours copying the key code and making it into a relatively simple demo. I hope it can help you find the problem quickly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants