77using Microsoft . Win32 ;
88using System ;
99using System . Collections . Generic ;
10+ using System . Diagnostics ;
1011using System . IO ;
1112using System . Linq ;
1213using System . Reflection ;
@@ -22,20 +23,9 @@ 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 ;
28-
2926 // Our Strategies for resolving references
3027 List < ResolutionStrategy > ResolutionStrategies ;
3128
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-
3929 public TestAssemblyResolver ( AssemblyLoadContext loadContext , string testAssemblyPath )
4030 {
4131 _loadContext = loadContext ;
@@ -47,34 +37,37 @@ public TestAssemblyResolver(AssemblyLoadContext loadContext, string testAssembly
4737
4838 private void InitializeResolutionStrategies ( AssemblyLoadContext loadContext , string testAssemblyPath )
4939 {
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.
40+ // Decide whether to try WindowsDeskTop and/or AspNetCore runtimes before any others.
41+ // We base this on direct references only, so we will eventually try each of them
42+ // later in case there are any indirect references.
5243 AssemblyDefinition assemblyDef = AssemblyDefinition . ReadAssembly ( testAssemblyPath ) ;
53- bool isWindowsDesktop = false ;
54- bool isAspNetCore = false ;
44+ bool tryWindowsDesktopFirst = false ;
45+ bool tryAspNetCoreFirst = false ;
5546 foreach ( var reference in assemblyDef . MainModule . GetTypeReferences ( ) )
5647 {
5748 string fn = reference . FullName ;
5849 if ( fn . StartsWith ( "System.Windows." ) || fn . StartsWith ( "PresentationFramework" ) )
59- isWindowsDesktop = true ;
50+ tryWindowsDesktopFirst = true ;
6051 if ( fn . StartsWith ( "Microsoft.AspNetCore." ) )
61- isAspNetCore = true ;
52+ tryAspNetCoreFirst = true ;
6253 }
6354
6455 // Initialize the list of ResolutionStrategies in the best order depending on
6556 // what we learned.
6657 ResolutionStrategies = new List < ResolutionStrategy > ( ) ;
6758
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 ) ) ;
59+ if ( tryWindowsDesktopFirst )
60+ ResolutionStrategies . Add ( new WindowsDesktopStrategy ( ) ) ;
61+ if ( tryAspNetCoreFirst )
62+ ResolutionStrategies . Add ( new AspNetCoreStrategy ( ) ) ;
63+
7264 ResolutionStrategies . Add ( new TrustedPlatformAssembliesStrategy ( ) ) ;
7365 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 ) ) ;
66+
67+ if ( ! tryWindowsDesktopFirst )
68+ ResolutionStrategies . Add ( new WindowsDesktopStrategy ( ) ) ;
69+ if ( ! tryAspNetCoreFirst )
70+ ResolutionStrategies . Add ( new AspNetCoreStrategy ( ) ) ;
7871 }
7972
8073 public void Dispose ( )
@@ -201,96 +194,58 @@ public override bool TryToResolve(
201194 }
202195 }
203196
204- public class AdditionalDirectoryStrategy : ResolutionStrategy
197+ public class AdditionalRuntimesStrategy : ResolutionStrategy
205198 {
206- private string _frameworkDirectory ;
199+ private IEnumerable < DotNet . RuntimeInfo > _additionalRuntimes ;
207200
208- public AdditionalDirectoryStrategy ( string frameworkDirectory )
201+ public AdditionalRuntimesStrategy ( string runtimeName )
209202 {
210- _frameworkDirectory = frameworkDirectory ;
203+ _additionalRuntimes = DotNet . GetRuntimes ( runtimeName ) ;
211204 }
212205
213- public override bool TryToResolve (
214- AssemblyLoadContext loadContext , AssemblyName assemblyName , out Assembly loadedAssembly )
206+ public override bool TryToResolve ( AssemblyLoadContext loadContext , AssemblyName assemblyName , out Assembly loadedAssembly )
215207 {
216208 loadedAssembly = null ;
217- if ( assemblyName . Version == null )
218- return false ;
219-
220- var versionDir = FindBestVersionDir ( _frameworkDirectory , assemblyName . Version ) ;
221209
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 ) ;
210+ DotNet . RuntimeInfo runtime ;
211+ if ( ! FindBestRuntime ( assemblyName , out runtime ) )
212+ return false ;
233213
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- }
241- }
214+ string candidate = Path . Combine ( runtime . Path , runtime . Version . ToString ( ) , assemblyName . Name + ".dll" ) ;
215+ if ( ! File . Exists ( candidate ) )
216+ return false ;
242217
243- return false ;
218+ loadedAssembly = loadContext . LoadFromAssemblyPath ( candidate ) ;
219+ return true ;
244220 }
245- }
246221
247- #endregion
222+ private bool FindBestRuntime ( AssemblyName assemblyName , out DotNet . RuntimeInfo bestRuntime )
223+ {
224+ bestRuntime = null ;
225+ var targetVersion = assemblyName . Version ;
248226
249- #region HelperMethods
227+ if ( targetVersion is null )
228+ return false ;
250229
251- private static string FindBestVersionDir ( string libraryDir , Version targetVersion )
252- {
253- string target = targetVersion . ToString ( ) ;
254- Version bestVersion = new Version ( 0 , 0 ) ;
255- foreach ( var subdir in Directory . GetDirectories ( libraryDir ) )
256- {
257- Version version ;
258- if ( TryGetVersionFromString ( Path . GetFileName ( subdir ) , out version ) )
230+ foreach ( var candidate in _additionalRuntimes )
259231 {
260- if ( version >= targetVersion )
261- if ( bestVersion . Major == 0 || bestVersion > version )
262- bestVersion = version ;
232+ if ( candidate . Version >= targetVersion )
233+ if ( bestRuntime is null || bestRuntime . Version > candidate . Version )
234+ bestRuntime = candidate ;
263235 }
264- }
265236
266- return bestVersion . Major > 0
267- ? bestVersion . ToString ( )
268- : null ;
237+ return bestRuntime is not null ;
238+ }
269239 }
270240
271- private static bool TryGetVersionFromString ( string text , out Version newVersion )
241+ public class WindowsDesktopStrategy : AdditionalRuntimesStrategy
272242 {
273- const string VERSION_CHARS = ".0123456789" ;
274-
275- int len = 0 ;
276- foreach ( char c in text )
277- {
278- if ( VERSION_CHARS . IndexOf ( c ) >= 0 )
279- len ++ ;
280- else
281- break ;
282- }
243+ public WindowsDesktopStrategy ( ) : base ( "Microsoft.WindowsDesktop.App" ) { }
244+ }
283245
284- try
285- {
286- newVersion = new Version ( text . Substring ( 0 , len ) ) ;
287- return true ;
288- }
289- catch
290- {
291- newVersion = new Version ( ) ;
292- return false ;
293- }
246+ public class AspNetCoreStrategy : AdditionalRuntimesStrategy
247+ {
248+ public AspNetCoreStrategy ( ) : base ( "Microsoft.AspNetCore.App" ) { }
294249 }
295250
296251 #endregion
0 commit comments