@@ -76,7 +76,7 @@ public InstrumenterResult Instrument()
76
76
private void InstrumentModule ( )
77
77
{
78
78
using ( var stream = new FileStream ( _module , FileMode . Open , FileAccess . ReadWrite ) )
79
- using ( var resolver = new DefaultAssemblyResolver ( ) )
79
+ using ( var resolver = new NetstandardAwareAssemblyResolver ( ) )
80
80
{
81
81
resolver . AddSearchDirectory ( Path . GetDirectoryName ( _module ) ) ;
82
82
var parameters = new ReaderParameters { ReadSymbols = true , AssemblyResolver = resolver } ;
@@ -602,4 +602,94 @@ public MethodReference ImportReference(MethodReference method, IGenericParameter
602
602
}
603
603
}
604
604
}
605
+
606
+ /// <summary>
607
+ /// In case of testing different runtime i.e. netfx we could find netstandard.dll in folder.
608
+ /// netstandard.dll is a forward only lib, there is no IL but only forwards to "runtime" implementation.
609
+ /// For some classes implementation are in different assembly for different runtime for instance:
610
+ ///
611
+ /// For NetFx 4.7
612
+ /// // Token: 0x2700072C RID: 1836
613
+ /// .class extern forwarder System.Security.Cryptography.X509Certificates.StoreName
614
+ /// {
615
+ /// .assembly extern System
616
+ /// }
617
+ ///
618
+ /// For netcoreapp2.2
619
+ /// Token: 0x2700072C RID: 1836
620
+ /// .class extern forwarder System.Security.Cryptography.X509Certificates.StoreName
621
+ /// {
622
+ /// .assembly extern System.Security.Cryptography.X509Certificates
623
+ /// }
624
+ ///
625
+ /// There is a concrete possibility that Cecil cannot find implementation and throws StackOverflow exception https://github.com/jbevain/cecil/issues/575
626
+ /// This custom resolver check if requested lib is a "official" netstandard.dll and load once of "current runtime" with
627
+ /// correct forwards.
628
+ /// Check compares 'assembly name' and 'public key token', because versions could differ between runtimes.
629
+ /// </summary>
630
+ internal class NetstandardAwareAssemblyResolver : DefaultAssemblyResolver
631
+ {
632
+ private static System . Reflection . Assembly _netStandardAssembly ;
633
+ private static string _name ;
634
+ private static byte [ ] _publicKeyToken ;
635
+ private static AssemblyDefinition _assemblyDefinition ;
636
+
637
+ static NetstandardAwareAssemblyResolver ( )
638
+ {
639
+ try
640
+ {
641
+ // To be sure to load information of "real" runtime netstandard implementation
642
+ _netStandardAssembly = System . Reflection . Assembly . LoadFile ( Path . Combine ( Path . GetDirectoryName ( typeof ( object ) . Assembly . Location ) , "netstandard.dll" ) ) ;
643
+ System . Reflection . AssemblyName name = _netStandardAssembly . GetName ( ) ;
644
+ _name = name . Name ;
645
+ _publicKeyToken = name . GetPublicKeyToken ( ) ;
646
+ _assemblyDefinition = AssemblyDefinition . ReadAssembly ( _netStandardAssembly . Location ) ;
647
+ }
648
+ catch ( FileNotFoundException )
649
+ {
650
+ // netstandard not supported
651
+ }
652
+ }
653
+
654
+ // Check name and public key but not version that could be different
655
+ private bool CheckIfSearchingNetstandard ( AssemblyNameReference name )
656
+ {
657
+ if ( _netStandardAssembly is null )
658
+ {
659
+ return false ;
660
+ }
661
+
662
+ if ( _name != name . Name )
663
+ {
664
+ return false ;
665
+ }
666
+
667
+ if ( name . PublicKeyToken . Length != _publicKeyToken . Length )
668
+ {
669
+ return false ;
670
+ }
671
+
672
+ for ( int i = 0 ; i < name . PublicKeyToken . Length ; i ++ )
673
+ {
674
+ if ( _publicKeyToken [ i ] != name . PublicKeyToken [ i ] )
675
+ {
676
+ return false ;
677
+ }
678
+ }
679
+
680
+ return true ;
681
+ }
682
+
683
+ public override AssemblyDefinition Resolve ( AssemblyNameReference name )
684
+ {
685
+ if ( CheckIfSearchingNetstandard ( name ) )
686
+ {
687
+ return _assemblyDefinition ;
688
+ }
689
+ else
690
+ {
691
+ return base . Resolve ( name ) ;
692
+ }
693
+ }
694
+ }
605
695
}
0 commit comments