@@ -86,6 +86,7 @@ class AssemblyResolver :
86
86
/// </summary>
87
87
private readonly object _syncLock = new ( ) ;
88
88
89
+ private static List < string > ? s_currentlyLoading ;
89
90
private bool _disposed ;
90
91
91
92
/// <summary>
@@ -335,7 +336,7 @@ protected virtual
335
336
if ( EqtTrace . IsInfoEnabled )
336
337
{
337
338
EqtTrace . Info (
338
- "AssemblyResolver: {0}: Failed to create assemblyName. Reason:{1} " ,
339
+ "MSTest. AssemblyResolver.OnResolve: Failed to create assemblyName '{0}' . Reason: {1} " ,
339
340
name ,
340
341
ex ) ;
341
342
}
@@ -344,7 +345,7 @@ protected virtual
344
345
return null ;
345
346
}
346
347
347
- DebugEx . Assert ( requestedName != null && ! StringEx . IsNullOrEmpty ( requestedName . Name ) , "AssemblyResolver.OnResolve: requested is null or name is empty!" ) ;
348
+ DebugEx . Assert ( requestedName != null && ! StringEx . IsNullOrEmpty ( requestedName . Name ) , "MSTest. AssemblyResolver.OnResolve: requested is null or name is empty!" ) ;
348
349
349
350
foreach ( string dir in searchDirectorypaths )
350
351
{
@@ -359,15 +360,39 @@ protected virtual
359
360
{
360
361
if ( EqtTrace . IsVerboseEnabled )
361
362
{
362
- EqtTrace . Verbose ( "AssemblyResolver: Searching assembly: {0} in the directory: {1}" , requestedName . Name , dir ) ;
363
+ EqtTrace . Verbose ( "MSTest. AssemblyResolver.OnResolve : Searching assembly ' {0}' in the directory ' {1}' " , requestedName . Name , dir ) ;
363
364
}
364
365
} ) ;
365
366
366
367
foreach ( string extension in new string [ ] { ".dll" , ".exe" } )
367
368
{
368
369
string assemblyPath = Path . Combine ( dir , requestedName . Name + extension ) ;
369
370
371
+ bool isPushed = false ;
372
+ bool isResource = requestedName . Name . EndsWith ( ".resources" , StringComparison . InvariantCulture ) ;
373
+ if ( isResource )
374
+ {
375
+ // Are we recursively looking up the same resource? Note - our backout code will set
376
+ // the ResourceHelper's currentlyLoading stack to null if an exception occurs.
377
+ if ( s_currentlyLoading != null && s_currentlyLoading . Count > 0 && s_currentlyLoading . LastIndexOf ( assemblyPath ) != - 1 )
378
+ {
379
+ EqtTrace . Info ( "MSTest.AssemblyResolver.OnResolve: Assembly '{0}' is searching for itself recursively '{1}', returning as not found." , name , assemblyPath ) ;
380
+ _resolvedAssemblies [ name ] = null ;
381
+ return null ;
382
+ }
383
+
384
+ s_currentlyLoading ??= new List < string > ( ) ;
385
+ s_currentlyLoading . Add ( assemblyPath ) ; // Push
386
+ isPushed = true ;
387
+ }
388
+
370
389
Assembly ? assembly = SearchAndLoadAssembly ( assemblyPath , name , requestedName , isReflectionOnly ) ;
390
+ if ( isResource && isPushed )
391
+ {
392
+ DebugEx . Assert ( s_currentlyLoading is not null , "_currentlyLoading should not be null" ) ;
393
+ s_currentlyLoading . RemoveAt ( s_currentlyLoading . Count - 1 ) ; // Pop
394
+ }
395
+
371
396
if ( assembly != null )
372
397
{
373
398
return assembly ;
@@ -447,7 +472,7 @@ private void WindowsRuntimeMetadataReflectionOnlyNamespaceResolve(object sender,
447
472
{
448
473
if ( StringEx . IsNullOrEmpty ( args . Name ) )
449
474
{
450
- Debug . Fail ( "AssemblyResolver.OnResolve: args.Name is null or empty." ) ;
475
+ Debug . Fail ( "MSTest. AssemblyResolver.OnResolve: args.Name is null or empty." ) ;
451
476
return null ;
452
477
}
453
478
@@ -457,7 +482,7 @@ private void WindowsRuntimeMetadataReflectionOnlyNamespaceResolve(object sender,
457
482
{
458
483
if ( EqtTrace . IsInfoEnabled )
459
484
{
460
- EqtTrace . Info ( "AssemblyResolver: Resolving assembly: {0}. " , args . Name ) ;
485
+ EqtTrace . Info ( "MSTest. AssemblyResolver.OnResolve : Resolving assembly ' {0}' " , args . Name ) ;
461
486
}
462
487
} ) ;
463
488
@@ -469,7 +494,7 @@ private void WindowsRuntimeMetadataReflectionOnlyNamespaceResolve(object sender,
469
494
{
470
495
if ( EqtTrace . IsInfoEnabled )
471
496
{
472
- EqtTrace . Info ( "AssemblyResolver: Resolving assembly after applying policy: {0}. " , assemblyNameToLoad ) ;
497
+ EqtTrace . Info ( "MSTest. AssemblyResolver.OnResolve : Resolving assembly after applying policy ' {0}' " , assemblyNameToLoad ) ;
473
498
}
474
499
} ) ;
475
500
@@ -482,62 +507,58 @@ private void WindowsRuntimeMetadataReflectionOnlyNamespaceResolve(object sender,
482
507
}
483
508
484
509
assembly = SearchAssembly ( _searchDirectories , assemblyNameToLoad , isReflectionOnly ) ;
485
-
486
510
if ( assembly != null )
487
511
{
488
512
return assembly ;
489
513
}
490
514
491
- if ( _directoryList != null && _directoryList . Count != 0 )
515
+ // required assembly is not present in searchDirectories??
516
+ // see, if we can find it in user specified search directories.
517
+ while ( assembly == null && _directoryList ? . Count > 0 )
492
518
{
493
- // required assembly is not present in searchDirectories??
494
- // see, if we can find it in user specified search directories.
495
- while ( assembly == null && _directoryList . Count > 0 )
496
- {
497
- // instead of loading whole search directory in one time, we are adding directory on the basis of need
498
- RecursiveDirectoryPath currentNode = _directoryList . Dequeue ( ) ;
499
-
500
- List < string > incrementalSearchDirectory = [ ] ;
519
+ // instead of loading whole search directory in one time, we are adding directory on the basis of need
520
+ RecursiveDirectoryPath currentNode = _directoryList . Dequeue ( ) ;
501
521
502
- if ( DoesDirectoryExist ( currentNode . DirectoryPath ) )
503
- {
504
- incrementalSearchDirectory . Add ( currentNode . DirectoryPath ) ;
505
-
506
- if ( currentNode . IncludeSubDirectories )
507
- {
508
- // Add all its sub-directory in depth first search order.
509
- AddSubdirectories ( currentNode . DirectoryPath , incrementalSearchDirectory ) ;
510
- }
522
+ List < string > incrementalSearchDirectory = [ ] ;
511
523
512
- // Add this directory list in this.searchDirectories so that when we will try to resolve some other
513
- // assembly, then it will look in this whole directory first.
514
- _searchDirectories . AddRange ( incrementalSearchDirectory ) ;
524
+ if ( DoesDirectoryExist ( currentNode . DirectoryPath ) )
525
+ {
526
+ incrementalSearchDirectory . Add ( currentNode . DirectoryPath ) ;
515
527
516
- assembly = SearchAssembly ( incrementalSearchDirectory , assemblyNameToLoad , isReflectionOnly ) ;
517
- }
518
- else
528
+ if ( currentNode . IncludeSubDirectories )
519
529
{
520
- // generate warning that path does not exist.
521
- SafeLog (
522
- assemblyNameToLoad ,
523
- ( ) =>
524
- {
525
- if ( EqtTrace . IsWarningEnabled )
526
- {
527
- EqtTrace . Warning (
528
- "The Directory: {0}, does not exist" ,
529
- currentNode . DirectoryPath ) ;
530
- }
531
- } ) ;
530
+ // Add all its sub-directory in depth first search order.
531
+ AddSubdirectories ( currentNode . DirectoryPath , incrementalSearchDirectory ) ;
532
532
}
533
- }
534
533
535
- if ( assembly != null )
534
+ // Add this directory list in this.searchDirectories so that when we will try to resolve some other
535
+ // assembly, then it will look in this whole directory first.
536
+ _searchDirectories . AddRange ( incrementalSearchDirectory ) ;
537
+
538
+ assembly = SearchAssembly ( incrementalSearchDirectory , assemblyNameToLoad , isReflectionOnly ) ;
539
+ }
540
+ else
536
541
{
537
- return assembly ;
542
+ // generate warning that path does not exist.
543
+ SafeLog (
544
+ assemblyNameToLoad ,
545
+ ( ) =>
546
+ {
547
+ if ( EqtTrace . IsWarningEnabled )
548
+ {
549
+ EqtTrace . Warning (
550
+ "MSTest.AssemblyResolver.OnResolve: the directory '{0}', does not exist" ,
551
+ currentNode . DirectoryPath ) ;
552
+ }
553
+ } ) ;
538
554
}
539
555
}
540
556
557
+ if ( assembly != null )
558
+ {
559
+ return assembly ;
560
+ }
561
+
541
562
// Try for default load for System dlls that can't be found in search paths. Needs to loaded just by name.
542
563
try
543
564
{
@@ -580,7 +601,7 @@ private void WindowsRuntimeMetadataReflectionOnlyNamespaceResolve(object sender,
580
601
{
581
602
if ( EqtTrace . IsInfoEnabled )
582
603
{
583
- EqtTrace . Info ( "AssemblyResolver: {0}: Failed to load assembly. Reason: {1}" , assemblyNameToLoad , ex ) ;
604
+ EqtTrace . Info ( "MSTest. AssemblyResolver.OnResolve: Failed to load assembly '{0}' . Reason: {1}" , assemblyNameToLoad , ex ) ;
584
605
}
585
606
} ) ;
586
607
}
@@ -609,7 +630,7 @@ private bool TryLoadFromCache(string assemblyName, bool isReflectionOnly, out As
609
630
{
610
631
if ( EqtTrace . IsInfoEnabled )
611
632
{
612
- EqtTrace . Info ( "AssemblyResolver: Resolved: {0}. " , assemblyName ) ;
633
+ EqtTrace . Info ( "MSTest. AssemblyResolver.OnResolve : Resolved ' {0}' " , assemblyName ) ;
613
634
}
614
635
} ) ;
615
636
return true ;
@@ -685,7 +706,7 @@ private static void SafeLog(string? assemblyName, Action loggerAction)
685
706
{
686
707
if ( EqtTrace . IsInfoEnabled )
687
708
{
688
- EqtTrace . Info ( "AssemblyResolver: Resolved assembly: {0}. " , assemblyName ) ;
709
+ EqtTrace . Info ( "MSTest. AssemblyResolver.OnResolve : Resolved assembly ' {0}' " , assemblyName ) ;
689
710
}
690
711
} ) ;
691
712
@@ -699,7 +720,7 @@ private static void SafeLog(string? assemblyName, Action loggerAction)
699
720
{
700
721
if ( EqtTrace . IsInfoEnabled )
701
722
{
702
- EqtTrace . Info ( "AssemblyResolver: Failed to load assembly: {0}. Reason:{1} " , assemblyName , ex ) ;
723
+ EqtTrace . Info ( "MSTest. AssemblyResolver.OnResolve : Failed to load assembly ' {0}' . Reason:{1} " , assemblyName , ex ) ;
703
724
}
704
725
} ) ;
705
726
@@ -717,7 +738,7 @@ private static void SafeLog(string? assemblyName, Action loggerAction)
717
738
{
718
739
if ( EqtTrace . IsInfoEnabled )
719
740
{
720
- EqtTrace . Info ( "AssemblyResolver: Failed to load assembly: {0}. Reason:{1} " , assemblyName , ex ) ;
741
+ EqtTrace . Info ( "MSTest. AssemblyResolver.OnResolve : Failed to load assembly ' {0}' . Reason:{1} " , assemblyName , ex ) ;
721
742
}
722
743
} ) ;
723
744
}
0 commit comments