views:

119

answers:

2

I've been searching for this for quite a while with no luck so far. Is there an equivalent to Java's ClassFileTransformer in .NET? Basically, I want to create a class CustomClassFileTransformer (which in Java would implement the interface ClassFileTransformer) that gets called whenever a class is loaded, and is allowed to tweak it and replace it with the tweaked version.

I know there are frameworks that do similar things, but I was looking for something more straightforward, like implementing my own ClassFileTransformer. Is it possible?


EDIT #1. More details about why I need this:

Basically, I have a C# application and I need to monitor the instructions it wants to run in order to detect read or write operations to fields (operations Ldfld and Stfld) and insert some instructions before the read/write takes place.

I know how to do this (except for the part where I need to be invoked to replace the class): for every method whose code I want to monitor, I must:

  1. Get the method's MethodBody using MethodBase.GetMethodBody()
  2. Transform it to byte array with MethodBody.GetILAsByteArray(). The byte[] it returns contains the bytecode.
  3. Analyse the bytecode as explained here, possibly inserting new instructions or deleting/modifying existing ones by changing the contents of the array.
  4. Create a new method and use the new bytecode to create its body, with MethodBuilder.CreateMethodBody(byte[] il, int count), where il is the array with the bytecode. I put all these tweaked methods in a new class and use the new class to replace the one that was originally going to be loaded.

An alternative to replacing classes would be somehow getting notified whenever a method is invoked. Then I'd replace the call to that method with a call to my own tweaked method, which I would tweak only the first time is invoked and then I'd put it in a dictionary for future uses, to reduce overhead (for future calls I'll just look up the method and invoke it; I won't need to analyse the bytecode again). I'm currently investigating ways to do this and LinFu looks pretty interesting, but if there was something like a ClassFileTransformer it would be much simpler: I just rewrite the class, replace it, and let the code run without monitoring anything.

An additional note: the classes may be sealed. I want to be able to replace any kind of class, I cannot impose restrictions on their attributes.


EDIT #2. Why I need to do this at runtime.

I need to monitor everything that is going on so that I can detect every access to data. This applies to the code of library classes as well. However, I cannot know in advance which classes are going to be used, and even if I knew every possible class that may get loaded it would be a huge performance hit to tweak all of them instead of waiting to see whether they actually get invoked or not.


POSSIBLE (BUT PRETTY HARDCORE) SOLUTION. In case anyone is interested (and I see the question has been faved, so I guess someone is), this is what I'm looking at right now. Basically I'd have to implement the profiling API and I'll register for the events that I'm interested in, in my case whenever a JIT compilation starts. An extract of the blogpost:

  • In your ICorProfilerCallback2::ModuleLoadFinished callback, you call ICorProfilerInfo2::GetModuleMetadata to get a pointer to a metadata interface on that module.
  • QI for the metadata interface you want. Search MSDN for "IMetaDataImport", and grope through the table of contents to find topics on the metadata interfaces.
  • Once you're in metadata-land, you have access to all the types in the module, including their fields and function prototypes. You may need to parse metadata signatures and this signature parser may be of use to you.
  • In your ICorProfilerCallback2::JITCompilationStarted callback, you may use ICorProfilerInfo2::GetILFunctionBody to inspect the original IL, and ICorProfilerInfo2::GetILFunctionBodyAllocator and then ICorProfilerInfo2::SetILFunctionBody to replace that IL with your own.

The great news: I get notified when a JIT compilation starts and I can replace the bytecode right there, without having to worry about replacing the class, etc. The not-so-great news: you cannot invoke managed code from the API's callback methods, which makes sense but means I'm on my own parsing the IL code, etc, as opposed to be able to use Cecil, which would've been a breeze.

I don't think there's a simpler way to do this without using AOP frameworks (such as PostSharp). If anyone has any other idea please let me know. I'm not marking the question as answered yet.

+1  A: 

I don't know of a direct equivalent in .NET for this.

However, there are some ways to implement similar functionality, such as using Reflection.Emit to generate assemblies and types on demand, uing RealProxy to create proxy objects for interfaces and MarshalByRefObject objects. However, to advise what to use, it would be important to know more about the actual use case.

Lucero
Yep, I know about the possible solutions you mention, but they don't allow me to replace classes (or at least I don't know how). I've updated my question with more details. Thanks for your answer :)
Alix
I see, you have done your homework. Still, I don't think that there is anything like Java's `ClassFileTransformer` in .NET, and I never came across something like that in any of the AOP, dynamic proxy and similar libraries which I looked at closely. There is a good overview on the Postsharp site: http://www.sharpcrafters.com/aop.net/runtime-weaving
Lucero
Yeah, I had also read the overview on the Potsharp site (I've done my homework indeed ;) ), but unfortunately it doesn't solve my problem. I'll keep investigating. Thanks again.
Alix
A: 

After quite some research I'm answering my own question: there isn't an equivalent to the ClassFileTransformer in .NET, or any straightforward way to replace classes.

It's possible to gain control over the class-loading process by hosting the CLR, but this is pretty low-level, you have to be careful with it, and it's not possible in every scenario. For example if you're running on a server you may not have the rights to host the CLR. Also if you're running an ASP.NET application you cannot do this because ASP.NET already provides a CLR host.

It's a pity .NET doesn't support this; it would be so easy for them to do this, they just have to notify you before a class is loaded and give you the chance to modify the class before passing it on the CLR to load it.

Alix