77using Microsoft . Win32 ;
88using System ;
99using System . Collections . Generic ;
10+ using System . Diagnostics ;
1011using System . IO ;
1112using System . Linq ;
1213using System . Reflection ;
@@ -22,59 +23,57 @@ internal sealed class TestAssemblyResolver : IDisposable
2223
2324 private readonly AssemblyLoadContext _loadContext ;
2425
25- private static readonly string INSTALL_DIR ;
26- private static readonly string WINDOWS_DESKTOP_DIR ;
27- private static readonly string ASP_NET_CORE_DIR ;
26+ private readonly IEnumerable < DotNet . RuntimeInfo > _windowsDesktopRuntimes ;
27+ private readonly IEnumerable < DotNet . RuntimeInfo > _aspNetCoreRuntimes ;
2828
2929 // Our Strategies for resolving references
3030 List < ResolutionStrategy > ResolutionStrategies ;
3131
32- static TestAssemblyResolver ( )
33- {
34- INSTALL_DIR = DotNet . GetInstallDirectory ( ) ;
35- WINDOWS_DESKTOP_DIR = Path . Combine ( INSTALL_DIR , "shared" , "Microsoft.WindowsDesktop.App" ) ;
36- ASP_NET_CORE_DIR = Path . Combine ( INSTALL_DIR , "shared" , "Microsoft.AspNetCore.App" ) ;
37- }
38-
3932 public TestAssemblyResolver ( AssemblyLoadContext loadContext , string testAssemblyPath )
4033 {
4134 _loadContext = loadContext ;
4235
36+ _windowsDesktopRuntimes = DotNet . GetRuntimes ( "Microsoft.WindowsDesktop.App" ) ;
37+ _aspNetCoreRuntimes = DotNet . GetRuntimes ( "Microsoft.AspNetCore.App" ) ;
38+
4339 InitializeResolutionStrategies ( loadContext , testAssemblyPath ) ;
4440
4541 _loadContext . Resolving += OnResolving ;
4642 }
4743
4844 private void InitializeResolutionStrategies ( AssemblyLoadContext loadContext , string testAssemblyPath )
4945 {
50- // First, looking only at direct references by the test assembly, try to determine if
51- // this assembly is using WindowsDesktop (either SWF or WPF) and/or AspNetCore.
46+ // Decide whether to try WindowsDeskTop and/or AspNetCore runtimes before any others.
47+ // We base this on direct references only, so we will eventually try each of them
48+ // later in case there are any indirect references.
5249 AssemblyDefinition assemblyDef = AssemblyDefinition . ReadAssembly ( testAssemblyPath ) ;
53- bool isWindowsDesktop = false ;
54- bool isAspNetCore = false ;
50+ bool tryWindowsDesktopFirst = false ;
51+ bool tryAspNetCoreFirst = false ;
5552 foreach ( var reference in assemblyDef . MainModule . GetTypeReferences ( ) )
5653 {
5754 string fn = reference . FullName ;
5855 if ( fn . StartsWith ( "System.Windows." ) || fn . StartsWith ( "PresentationFramework" ) )
59- isWindowsDesktop = true ;
56+ tryWindowsDesktopFirst = true ;
6057 if ( fn . StartsWith ( "Microsoft.AspNetCore." ) )
61- isAspNetCore = true ;
58+ tryAspNetCoreFirst = true ;
6259 }
6360
6461 // Initialize the list of ResolutionStrategies in the best order depending on
6562 // what we learned.
6663 ResolutionStrategies = new List < ResolutionStrategy > ( ) ;
6764
68- if ( isWindowsDesktop && Directory . Exists ( WINDOWS_DESKTOP_DIR ) )
69- ResolutionStrategies . Add ( new AdditionalDirectoryStrategy ( WINDOWS_DESKTOP_DIR ) ) ;
70- if ( isAspNetCore && Directory . Exists ( ASP_NET_CORE_DIR ) )
71- ResolutionStrategies . Add ( new AdditionalDirectoryStrategy ( ASP_NET_CORE_DIR ) ) ;
65+ if ( tryWindowsDesktopFirst )
66+ ResolutionStrategies . Add ( new WindowsDesktopStrategy ( ) ) ;
67+ if ( tryAspNetCoreFirst )
68+ ResolutionStrategies . Add ( new AspNetCoreStrategy ( ) ) ;
69+
7270 ResolutionStrategies . Add ( new TrustedPlatformAssembliesStrategy ( ) ) ;
7371 ResolutionStrategies . Add ( new RuntimeLibrariesStrategy ( loadContext , testAssemblyPath ) ) ;
74- if ( ! isWindowsDesktop && Directory . Exists ( WINDOWS_DESKTOP_DIR ) )
75- ResolutionStrategies . Add ( new AdditionalDirectoryStrategy ( WINDOWS_DESKTOP_DIR ) ) ;
76- if ( ! isAspNetCore && Directory . Exists ( ASP_NET_CORE_DIR ) )
77- ResolutionStrategies . Add ( new AdditionalDirectoryStrategy ( ASP_NET_CORE_DIR ) ) ;
72+
73+ if ( ! tryWindowsDesktopFirst )
74+ ResolutionStrategies . Add ( new WindowsDesktopStrategy ( ) ) ;
75+ if ( ! tryAspNetCoreFirst )
76+ ResolutionStrategies . Add ( new AspNetCoreStrategy ( ) ) ;
7877 }
7978
8079 public void Dispose ( )
@@ -201,49 +200,60 @@ public override bool TryToResolve(
201200 }
202201 }
203202
204- public class AdditionalDirectoryStrategy : ResolutionStrategy
203+ public class AdditionalRuntimesStrategy : ResolutionStrategy
205204 {
206- private string _frameworkDirectory ;
205+ private IEnumerable < DotNet . RuntimeInfo > _additionalRuntimes ;
207206
208- public AdditionalDirectoryStrategy ( string frameworkDirectory )
207+ public AdditionalRuntimesStrategy ( string runtimeName )
209208 {
210- _frameworkDirectory = frameworkDirectory ;
209+ _additionalRuntimes = DotNet . GetRuntimes ( runtimeName ) ;
211210 }
212211
213- public override bool TryToResolve (
214- AssemblyLoadContext loadContext , AssemblyName assemblyName , out Assembly loadedAssembly )
212+ public override bool TryToResolve ( AssemblyLoadContext loadContext , AssemblyName assemblyName , out Assembly loadedAssembly )
215213 {
216214 loadedAssembly = null ;
217- if ( assemblyName . Version == null )
215+
216+ DotNet . RuntimeInfo runtime ;
217+ if ( ! FindBestRuntime ( assemblyName , out runtime ) )
218218 return false ;
219219
220- var versionDir = FindBestVersionDir ( _frameworkDirectory , assemblyName . Version ) ;
220+ string candidate = Path . Combine ( runtime . Path , runtime . Version . ToString ( ) , assemblyName . Name + ".dll" ) ;
221+ if ( ! File . Exists ( candidate ) )
222+ return false ;
221223
222- if ( versionDir != null )
223- {
224- string candidate = Path . Combine ( _frameworkDirectory , versionDir , assemblyName . Name + ".dll" ) ;
225- if ( File . Exists ( candidate ) )
226- {
227- loadedAssembly = loadContext . LoadFromAssemblyPath ( candidate ) ;
228- log . Info ( "'{0}' ({1}) assembly is loaded from AdditionalFrameworkDirectory {2} dependencies with best candidate version {3}" ,
229- assemblyName ,
230- loadedAssembly . Location ,
231- _frameworkDirectory ,
232- versionDir ) ;
224+ loadedAssembly = loadContext . LoadFromAssemblyPath ( candidate ) ;
225+ return true ;
226+ }
233227
234- return true ;
235- }
236- else
237- {
238- log . Debug ( "Best version dir for {0} is {1}, but there is no {2} file" , _frameworkDirectory , versionDir , candidate ) ;
239- return false ;
240- }
228+ private bool FindBestRuntime ( AssemblyName assemblyName , out DotNet . RuntimeInfo bestRuntime )
229+ {
230+ bestRuntime = null ;
231+ var targetVersion = assemblyName . Version ;
232+
233+ if ( targetVersion is null )
234+ return false ;
235+
236+ foreach ( var candidate in _additionalRuntimes )
237+ {
238+ if ( candidate . Version >= targetVersion )
239+ if ( bestRuntime is null || bestRuntime . Version > candidate . Version )
240+ bestRuntime = candidate ;
241241 }
242242
243- return false ;
243+ return bestRuntime is not null ;
244244 }
245245 }
246246
247+ public class WindowsDesktopStrategy : AdditionalRuntimesStrategy
248+ {
249+ public WindowsDesktopStrategy ( ) : base ( "Microsoft.WindowsDesktop.App" ) { }
250+ }
251+
252+ public class AspNetCoreStrategy : AdditionalRuntimesStrategy
253+ {
254+ public AspNetCoreStrategy ( ) : base ( "Microsoft.AspNetCore.App" ) { }
255+ }
256+
247257 #endregion
248258
249259 #region HelperMethods
0 commit comments