Skip to content

Commit 964e9e5

Browse files
safernjoperezr
authored andcommitted
Improve loading of Roslyn assemblies on validate package task (#22277)
* Improve loading of Roslyn assemblies on validate package task * PR Feedback
1 parent 278b73b commit 964e9e5

File tree

2 files changed

+42
-8
lines changed

2 files changed

+42
-8
lines changed

src/Compatibility/Microsoft.DotNet.Compatibility/ValidatePackage.cs

+39-6
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33

44
using System;
55
using System.Collections.Generic;
6-
using System.Diagnostics;
76
using System.IO;
87
using System.Reflection;
98
using Microsoft.Build.Framework;
109
using Microsoft.DotNet.PackageValidation;
1110
using Microsoft.NET.Build.Tasks;
1211
using NuGet.RuntimeModel;
12+
#if NETCOREAPP
13+
using System.Runtime.Loader;
14+
#endif
1315

1416
namespace Microsoft.DotNet.Compatibility
1517
{
@@ -43,14 +45,23 @@ public class ValidatePackage : TaskBase
4345

4446
public override bool Execute()
4547
{
48+
#if NETCOREAPP
49+
AssemblyLoadContext currentContext = AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly());
50+
currentContext.Resolving += ResolverForRoslyn;
51+
#else
4652
AppDomain.CurrentDomain.AssemblyResolve += ResolverForRoslyn;
53+
#endif
4754
try
4855
{
4956
return base.Execute();
5057
}
5158
finally
5259
{
60+
#if NETCOREAPP
61+
currentContext.Resolving -= ResolverForRoslyn;
62+
#else
5363
AppDomain.CurrentDomain.AssemblyResolve -= ResolverForRoslyn;
64+
#endif
5465
}
5566
}
5667

@@ -103,19 +114,41 @@ protected override void ExecuteCore()
103114
}
104115
}
105116

117+
#if NETCOREAPP
118+
private Assembly ResolverForRoslyn(AssemblyLoadContext context, AssemblyName assemblyName)
119+
{
120+
return LoadRoslyn(assemblyName, path => context.LoadFromAssemblyPath(path));
121+
}
122+
#else
106123
private Assembly ResolverForRoslyn(object sender, ResolveEventArgs args)
107124
{
108125
AssemblyName name = new(args.Name);
109-
if (name.Name == "Microsoft.CodeAnalysis" || name.Name == "Microsoft.CodeAnalysis.CSharp")
126+
return LoadRoslyn(name, path => Assembly.LoadFrom(path));
127+
}
128+
#endif
129+
130+
private Assembly LoadRoslyn(AssemblyName name, Func<string, Assembly> loadFromPath)
131+
{
132+
const string codeAnalysisName = "Microsoft.CodeAnalysis";
133+
const string codeAnalysisCsharpName = "Microsoft.CodeAnalysis.CSharp";
134+
if (name.Name == codeAnalysisName || name.Name == codeAnalysisCsharpName)
110135
{
111-
Assembly asm = Assembly.LoadFrom(Path.Combine(RoslynAssembliesPath, $"{name.Name}.dll"));
112-
Version version = asm.GetName().Version;
113-
if (version < name.Version)
136+
Assembly asm = loadFromPath(Path.Combine(RoslynAssembliesPath, $"{name.Name}.dll"));
137+
Version resolvedVersion = asm.GetName().Version;
138+
if (resolvedVersion < name.Version)
114139
{
115-
throw new Exception(string.Format(Resources.UpdateSdkVersion, version, name.Version));
140+
throw new Exception(string.Format(Resources.UpdateSdkVersion, resolvedVersion, name.Version));
116141
}
142+
143+
// Being extra defensive but we want to avoid that we accidentally load two different versions of either
144+
// of the roslyn assemblies from a different location, so let's load them both on the first request.
145+
Assembly _ = name.Name == codeAnalysisName ?
146+
loadFromPath(Path.Combine(RoslynAssembliesPath, $"{codeAnalysisCsharpName}.dll")) :
147+
loadFromPath(Path.Combine(RoslynAssembliesPath, $"{codeAnalysisName}.dll"));
148+
117149
return asm;
118150
}
151+
119152
return null;
120153
}
121154
}

src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Compatibility.Common.targets

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
<PropertyGroup Condition="'$(RoslynAssembliesPath)' == ''">
1616
<RoslynAssembliesPath>$(RoslynTargetsPath)</RoslynAssembliesPath>
1717
<_packageReferenceList>@(PackageReference)</_packageReferenceList>
18-
<RoslynAssembliesPath Condition="'$(MSBuildProjectExtension)' == '.csproj' and $(_packageReferenceList.Contains('Microsoft.Net.Compilers.Toolset'))">$([System.IO.Path]::GetDirectoryName($(CSharpCoreTargetsPath)))</RoslynAssembliesPath>
19-
<RoslynAssembliesPath Condition="'$(MSBuildProjectExtension)' == '.vbproj' and $(_packageReferenceList.Contains('Microsoft.Net.Compilers.Toolset'))">$([System.IO.Path]::GetDirectoryName($(VisualBasicCoreTargetsPath)))</RoslynAssembliesPath>
18+
<!-- CSharpCoreTargetsPath and VisualBasicCoreTargetsPath point to the same location, Microsoft.CodeAnalysis.CSharp and Microsoft.CodeAnalysis.VisualBasic
19+
are on the same directory as Microsoft.CodeAnalysis. So there is no need to distinguish between csproj or vbproj. -->
20+
<RoslynAssembliesPath Condition="$(_packageReferenceList.Contains('Microsoft.Net.Compilers.Toolset'))">$([System.IO.Path]::GetDirectoryName($(CSharpCoreTargetsPath)))</RoslynAssembliesPath>
2021
<RoslynAssembliesPath Condition="'$(MSBuildRuntimeType)' == 'Core'">$([System.IO.Path]::Combine('$(RoslynAssembliesPath)', bincore))</RoslynAssembliesPath>
2122
</PropertyGroup>
2223

0 commit comments

Comments
 (0)