@@ -86,6 +86,7 @@ class AssemblyResolver :
8686 /// </summary>
8787 private readonly object _syncLock = new ( ) ;
8888
89+ private static List < string > ? s_currentlyLoading ;
8990 private bool _disposed ;
9091
9192 /// <summary>
@@ -335,7 +336,7 @@ protected virtual
335336 if ( EqtTrace . IsInfoEnabled )
336337 {
337338 EqtTrace . Info (
338- "AssemblyResolver: {0}: Failed to create assemblyName. Reason:{1} " ,
339+ "MSTest. AssemblyResolver.OnResolve: Failed to create assemblyName '{0}' . Reason: {1} " ,
339340 name ,
340341 ex ) ;
341342 }
@@ -344,7 +345,7 @@ protected virtual
344345 return null ;
345346 }
346347
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!" ) ;
348349
349350 foreach ( string dir in searchDirectorypaths )
350351 {
@@ -359,15 +360,39 @@ protected virtual
359360 {
360361 if ( EqtTrace . IsVerboseEnabled )
361362 {
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 ) ;
363364 }
364365 } ) ;
365366
366367 foreach ( string extension in new string [ ] { ".dll" , ".exe" } )
367368 {
368369 string assemblyPath = Path . Combine ( dir , requestedName . Name + extension ) ;
369370
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+
370389 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+
371396 if ( assembly != null )
372397 {
373398 return assembly ;
@@ -447,7 +472,7 @@ private void WindowsRuntimeMetadataReflectionOnlyNamespaceResolve(object sender,
447472 {
448473 if ( StringEx . IsNullOrEmpty ( args . Name ) )
449474 {
450- Debug . Fail ( "AssemblyResolver.OnResolve: args.Name is null or empty." ) ;
475+ Debug . Fail ( "MSTest. AssemblyResolver.OnResolve: args.Name is null or empty." ) ;
451476 return null ;
452477 }
453478
@@ -457,7 +482,7 @@ private void WindowsRuntimeMetadataReflectionOnlyNamespaceResolve(object sender,
457482 {
458483 if ( EqtTrace . IsInfoEnabled )
459484 {
460- EqtTrace . Info ( "AssemblyResolver: Resolving assembly: {0}. " , args . Name ) ;
485+ EqtTrace . Info ( "MSTest. AssemblyResolver.OnResolve : Resolving assembly ' {0}' " , args . Name ) ;
461486 }
462487 } ) ;
463488
@@ -469,7 +494,7 @@ private void WindowsRuntimeMetadataReflectionOnlyNamespaceResolve(object sender,
469494 {
470495 if ( EqtTrace . IsInfoEnabled )
471496 {
472- EqtTrace . Info ( "AssemblyResolver: Resolving assembly after applying policy: {0}. " , assemblyNameToLoad ) ;
497+ EqtTrace . Info ( "MSTest. AssemblyResolver.OnResolve : Resolving assembly after applying policy ' {0}' " , assemblyNameToLoad ) ;
473498 }
474499 } ) ;
475500
@@ -482,62 +507,58 @@ private void WindowsRuntimeMetadataReflectionOnlyNamespaceResolve(object sender,
482507 }
483508
484509 assembly = SearchAssembly ( _searchDirectories , assemblyNameToLoad , isReflectionOnly ) ;
485-
486510 if ( assembly != null )
487511 {
488512 return assembly ;
489513 }
490514
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 )
492518 {
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 ( ) ;
501521
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 = [ ] ;
511523
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 ) ;
515527
516- assembly = SearchAssembly ( incrementalSearchDirectory , assemblyNameToLoad , isReflectionOnly ) ;
517- }
518- else
528+ if ( currentNode . IncludeSubDirectories )
519529 {
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 ) ;
532532 }
533- }
534533
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
536541 {
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+ } ) ;
538554 }
539555 }
540556
557+ if ( assembly != null )
558+ {
559+ return assembly ;
560+ }
561+
541562 // Try for default load for System dlls that can't be found in search paths. Needs to loaded just by name.
542563 try
543564 {
@@ -580,7 +601,7 @@ private void WindowsRuntimeMetadataReflectionOnlyNamespaceResolve(object sender,
580601 {
581602 if ( EqtTrace . IsInfoEnabled )
582603 {
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 ) ;
584605 }
585606 } ) ;
586607 }
@@ -609,7 +630,7 @@ private bool TryLoadFromCache(string assemblyName, bool isReflectionOnly, out As
609630 {
610631 if ( EqtTrace . IsInfoEnabled )
611632 {
612- EqtTrace . Info ( "AssemblyResolver: Resolved: {0}. " , assemblyName ) ;
633+ EqtTrace . Info ( "MSTest. AssemblyResolver.OnResolve : Resolved ' {0}' " , assemblyName ) ;
613634 }
614635 } ) ;
615636 return true ;
@@ -685,7 +706,7 @@ private static void SafeLog(string? assemblyName, Action loggerAction)
685706 {
686707 if ( EqtTrace . IsInfoEnabled )
687708 {
688- EqtTrace . Info ( "AssemblyResolver: Resolved assembly: {0}. " , assemblyName ) ;
709+ EqtTrace . Info ( "MSTest. AssemblyResolver.OnResolve : Resolved assembly ' {0}' " , assemblyName ) ;
689710 }
690711 } ) ;
691712
@@ -699,7 +720,7 @@ private static void SafeLog(string? assemblyName, Action loggerAction)
699720 {
700721 if ( EqtTrace . IsInfoEnabled )
701722 {
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 ) ;
703724 }
704725 } ) ;
705726
@@ -717,7 +738,7 @@ private static void SafeLog(string? assemblyName, Action loggerAction)
717738 {
718739 if ( EqtTrace . IsInfoEnabled )
719740 {
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 ) ;
721742 }
722743 } ) ;
723744 }
0 commit comments