/src/LinFu.AOP/Loaders/JITWeaver.cs
C# | 102 lines | 52 code | 20 blank | 30 comment | 12 complexity | 01f6abf8f700c156764a22d97f928af6 MD5 | raw file
1using System; 2using System.Collections.Generic; 3using System.IO; 4using System.Reflection; 5using LinFu.AOP.Cecil.Interfaces; 6using LinFu.Reflection; 7using LinFu.Reflection.Emit; 8using Mono.Cecil; 9 10namespace LinFu.AOP.Cecil.Loaders 11{ 12 /// <summary> 13 /// Represents a loader that modifies a given assembly prior to being loaded from disk. 14 /// </summary> 15 public class JITWeaver : AssemblyLoader 16 { 17 private readonly List<Action<AssemblyDefinition>> _assemblyWeavers = new List<Action<AssemblyDefinition>>(); 18 19 /// <summary> 20 /// Initializes a new instance of the <see cref="JITWeaver" /> class. 21 /// </summary> 22 public JITWeaver() 23 : this(new PdbLoader()) 24 { 25 } 26 27 /// <summary> 28 /// Initializes a new instance of the <see cref="JITWeaver" /> class. 29 /// </summary> 30 /// <param name="pdbLoader">The loader that will be responsible for loading the program debugging information into memory.</param> 31 public JITWeaver(IPdbLoader pdbLoader) 32 { 33 PdbLoader = pdbLoader; 34 } 35 36 /// <summary> 37 /// Gets or sets the value indicating the <see cref="IPdbLoader" /> that will be used to load debug symbols into 38 /// memory. 39 /// </summary> 40 public IPdbLoader PdbLoader { get; set; } 41 42 /// <summary> 43 /// Gets the value indicating the list of <see cref="Action{T}" /> delegates 44 /// that will be used to modify the assemblies loaded into memory. 45 /// </summary> 46 public virtual IList<Action<AssemblyDefinition>> AssemblyWeavers => _assemblyWeavers; 47 48 /// <summary> 49 /// Gets or sets the value indicating the <see cref="IVerifier" /> 50 /// instance that will be used to ensure that the modified assemblies are valid. 51 /// </summary> 52 public virtual IVerifier AssemblyVerifier { get; set; } 53 54 /// <summary> 55 /// Modifies a given assembly prior to being loaded from disk. 56 /// </summary> 57 /// <param name="assemblyFile">The filename of the target assembly.</param> 58 /// <returns>A valid assembly.</returns> 59 public override Assembly Load(string assemblyFile) 60 { 61 var targetAssembly = AssemblyDefinition.ReadAssembly(assemblyFile); 62 63 // Strongly-named assemblies cannot be modified 64 if (targetAssembly.Name.HasPublicKey) 65 return base.Load(assemblyFile); 66 67 var assemblyFileName = Path.GetFileNameWithoutExtension(assemblyFile); 68 69 var pdbFile = string.Format("{0}.pdb", assemblyFileName); 70 var hasSymbols = File.Exists(pdbFile); 71 72 if (PdbLoader != null && hasSymbols) 73 PdbLoader.LoadSymbols(targetAssembly); 74 75 foreach (var action in AssemblyWeavers) 76 { 77 action(targetAssembly); 78 79 // Verify the assembly at every step 80 if (AssemblyVerifier == null) 81 continue; 82 83 AssemblyVerifier.Verify(targetAssembly); 84 } 85 86 var memoryStream = new MemoryStream(); 87 88 if (PdbLoader != null && hasSymbols) 89 PdbLoader.SaveSymbols(targetAssembly); 90 91 // Save the modifed assembly 92 targetAssembly.Save(memoryStream); 93 94 if (PdbLoader == null || !hasSymbols) 95 return targetAssembly.ToAssembly(); 96 97 var pdbBytes = File.ReadAllBytes(pdbFile); 98 99 return PdbLoader.LoadAssembly(memoryStream.ToArray(), pdbBytes); 100 } 101 } 102}