There are a a lot of questions and answers around AOP in .NET here on Stack Overflow, often mentioning PostSharp and other third-party products. So there seems to be qu
I was able to solve the problem with Mono.Cecil. I am still amazed how easy to learn, easy to use, and powerful it is. The almost complete lack of documentation did not change that.
These are the 3 sources of documentation I used:
The first link provides a very gentle introduction, but as it describes an older version of Cecil - and much has changed in the meantime - the second link was very helpful in translating the introduction to Cecil 0.9. After getting started, the (also not documented) source code was invaluable and answered every question I had - expect perhaps those about the .NET platform in general, but there's tons of books and material on that somewhere online I'm sure.
I can now take a DLL or EXE file, modify it, and write it back to disk. The only thing that I haven't done yet is figuring out how to keep debugging information - file name, line number, etc. currently get lost after writing the DLL or EXE file. My background isn't .NET, so I'm guessing here, and my guess would be that I need to look at mono.cecil.pdb to fix that. Somewhere later - it's not that super important for me right now. I'm creating this EXE file, run the application - and it's a complex GUI application, grown over many years with all the baggage you would expect to find in such a piece of, ahem, software - and it checks things and logs errors for me.
Here's the gist of my code:
DefaultAssemblyResolver assemblyResolver = new DefaultAssemblyResolver();
// so it won't complain about not finding assemblies sitting in the same directory as the dll/exe we are going to patch
assemblyResolver.AddSearchDirectory(assemblyDirectory);
var readerParameters = new ReaderParameters { AssemblyResolver = assemblyResolver };
AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(assemblyFilename, readerParameters);
foreach (var moduleDefinition in assembly.Modules)
{
foreach (var type in ModuleDefinitionRocks.GetAllTypes(moduleDefinition))
{
foreach (var method in type.Methods)
{
if (!HasAttribute("MyCustomAttribute", method.method.CustomAttributes)
{
ILProcessor ilProcessor = method.Body.GetILProcessor();
ilProcessor.InsertBefore(method.Body.Instructions.First(), ilProcessor.Create(OpCodes.Call, threadCheckerMethod));
// ...
private static bool HasAttribute(string attributeName, IEnumerable customAttributes)
{
return GetAttributeByName(attributeName, customAttributes) != null;
}
private static CustomAttribute GetAttributeByName(string attributeName, IEnumerable customAttributes)
{
foreach (var attribute in customAttributes)
if (attribute.AttributeType.FullName == attributeName)
return attribute;
return null;
}
If someone knows an easier way how to get this done, I'm still interested in an answer and I won't mark this as the solution - unless no easier solutions show up.