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