ReBuildAll Blog
Thoughts (mostly) on .NET development

Overriding virtual methods at runtime   (Framework)   
I was faced with a problem where I had a big bunch of Web service proxy classes, generated from their WSDL descriptions. I needed to override one virtual method of the base class to provide some custom code in the proxy class. This however presented two problems:

- I have many proxy classes in which I want to include this new functionality. These are in many different projects.
- The proxy classes are generated, so when they would be regenerated the code change would need to be reapplied.

The second point could be solved by deriving yet another class from the proxy class (or by using partial classes). This way the changes would live through regeneration cycles, but would create me twice as much classes, and managing changes in these new classes would still be a problem. Not to mention this would require recompiling and redeploying and reconfiguring all the applications.

I ended up using a much different solution using reflection and code emit. This allows for ease of maintainability and allows me to apply the new features without code changes or recompilation in the existing projects.

The .NET Framework provides very good code emiting capabilities: you can create .NET code on the fly, dynamically, and then call it right away. While this was probably aimed at scripting engines, it does give me a solution to the problem. When I will need to call a method from a proxy class I will generate a new derived class dynamically and override the method in question. The proxy classes were being used through reflection to begin with, so not much change is required: I can just pass in the Type instance of the generated class instead of the original, and everything should work.

There are some minor problems with this solution. First, the method body has to be provided in IL - Intermediate Language. That is like writing code in assembly language for the x86 platform, not very friendly. I was able to partly navigate around this problem by creating a new static class that provides the functionality I want, and calling this class from the new overriden method. Another solution would have been to write the code myself in C#, compile, and then use either ILDASM or REFLECTOR to copy the IL generated into my project. Anyhow, I ended up studying a little bit of IL, which was actually quite fun :-)

So how do you create code on the fly? Lets suppose I have a class called MyOriginalClass. It is a generated proxy class, derived from SoapHttpClientProtocol. I want to provide an implementation for the GetWebRequest() method, that is a protected virtual method.

So I started by getting the type of the original class. Now I can create a new Assembly and Module. Think of the Assembly as containing the metadata and the Module as containing the actual code - you can find more about this in MSDN.

Type typeofOriginal = typeof ( MyOriginalClass );

AssemblyName asmName = new AssemblyName ( "Test" );
AssemblyBuilder asmBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly (
    asmName,
    AssemblyBuilderAccess.RunAndSave );

ModuleBuilder modBuilder =
asmBuilder.DefineDynamicModule (
    asmName.Name,
    asmName.Name + ".dll" );


The code above creates a new assembly named Test. The module is just named using the same syntax, getting the .DLL extension. These is all done dynamically, so nothing is written to disc. Next step is creating the new class, that will derive from my original class.

TypeBuilder typeBuilder = modBuilder.DefineType (
    typeofOriginal.Name + "WithoutKeepAlive",
    TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class,
    typeofOriginal );


The new class has the name of the original one with WithoutKeepAlive added to the end. And it of course has the original class as its base class. So now it is time to generate our new overriden method. This will simply call MyNewClass.GetWebRequest() method, which is a public static method I define elsewhere. By calling this method I get away with writing as little IL as possible.

// create a new method
MethodBuilder methodBuilder = typeBuilder.DefineMethod (
    "GetWebRequest",
    MethodAttributes.Public | MethodAttributes.ReuseSlot |
      MethodAttributes.HideBySig | MethodAttributes.Virtual,
    typeof ( System.Net.WebRequest ),
    new Type[] { typeof ( Uri ) } );

// get IL generator instance
ILGenerator ilgen = methodBuilder.GetILGenerator ();

// declare local variable
LocalBuilder localBuilder =
ilgen.DeclareLocal ( typeof ( System.Net.WebRequest ) );

// create method body in IL
ilgen.Emit ( OpCodes.Ldarg_1 );
ilgen.Emit (
    OpCodes.Call,
    typeof ( MyNewClass ).GetMethod (
        "GetWebRequest",
        BindingFlags.Static | BindingFlags.Public ) );
   ilgen.Emit ( OpCodes.Stloc_0 );
   ilgen.Emit ( OpCodes.Ldloc_0 );
   ilgen.Emit ( OpCodes.Ret );


Well, that is about it. At this point I can either save the new assembly to disc, or start using it right away. The proxy class has a HelloWebService() method that that is making a Web service call. If I invoke this on the original class nothing new happens. However, if I invoke it on the new class, my static method will be called (through the new override method).

// finish code generation and create type
Type newType = typeBuilder.CreateType ();

// create new instance of the class
object client = Activator.CreateInstance ( newType );

// call web service
MethodInfo minf =
    newType.GetMethod (
        "HelloWebService",
        new Type[] { typeof ( string ) } );
        minf.Invoke ( client, new object[] { "World" } );


That is about it. By writing more IL you could create a solution that does not require the use of another class. But this solution works perfectly fine for me.

Of course it would be wise to cache the types created this way, so they can be reused when another call is to be made. Types created this way remain loaded in the application domain until the entire domain is unloaded, so creating them all the time is bad idea. Code is not garbage collected.

 

Comments

r.w. Re: Overriding virtual methods at runtime
never mind, i got it...
r.w. Re: Overriding virtual methods at runtime
Hello LennardG,
I do have problems with replacing the GetWebRequest.
Is there some additional trick to override the method if it is generated via ServiceDescriptionImporter ?

Btw: great article :-)