Introduction
Do you have a distributed .NET application from the pre-WCF days that you want to migrate to WCF, but you either don't have the source because it's a third party component, or you can't change the source because your boss can't or won't make the jump to .NET 3.0? You just need to decorate your interfaces with some attributes which would be incredibly simple if you could modify the source code, but in those cases where you can't, it's not much harder to modify the MSIL.
Background
I have all these applications built for .NET remoting that are being actively maintained in a .NET 1.1 environment. When I built them, I split out the interface code from the implementation code because the interfaces are distributed in an assembly to clients and the implementation is in a server side assembly. This is exactly the way you would organize your ServiceContract
in WCF, but I need one more thing to host the code in a WCF ServiceHost - the attributes. It would be really nice to add the [ServiceContract]
and [OperationContract]
attributes to my interface, but that means I have to recompile my interface library under .NET 3.0 and also branch my source control projects to maintain the separate versions, just to add some silly attributes. The more I think about it, that' s probably easier than updating the MSIL, but in some cases with legacy code, that isn't an option.
To port that old remoting application assembly over to WCF, the process is pretty simple:
- Use ILDASM to disassemble your assembly into MSIL
- Use your favorite text editor to add IL for referencing the assembly where the attributes are defined (
System.ServiceModel
), and then add IL for the attributes themselves to the interface and methods (ServiceContract
and OperationContract
) - Use ILASM to assemble your MSIL back into an assembly with your new attributes
Tedious? A little, but not as bad as trying to talk your boss into dropping .NET 1.1 support.
Disassembly
The easy part. Just make sure you aren't violating any license agreements here if you're working with third party code. They usually have a clause about how you better not disassemble it. If they do, turn back now and ask them to do this for you. Use the ildasm version (and later on, ilasm) that the existing assembly is built with to ensure you'll keep compatibility in your legacy environment. My assembly currently runs under .NET 1.1, so I'm using ildasm version 1.1.4322.573.
ildasm <assembly>.dll /out=<assembly>.il
Now you've probably got two files - the MSIL files (<assembly>.il) and the resource file (<assembly>.res). Open the MSIL file in your favorite text editor. Since you're digging into MSIL, you should make your background black and your text bright green Courier font so it's exactly how movie producers envisioned programmers hacking executables back in 1979.
You'll probably also find it helpful to disassemble an assembly from a working WCF project so you can see how the attributes are applied by the compiler.
Modification to IL
Tedious, but still easy. You need to add the referenced assembly to the top of the MSIL, where you'll find any other assembly references, like mscorlib and System:
.assembly extern System.ServiceModel
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
.ver 3:0:0:0
}
Now you need to find the interface. It will start with .class interface public abstract
. Just below the curly brace but before the first .method
, you need to add the [ServiceContract]
attribute MSIL:
.class interface public abstract auto ansi IMyServiceInterface
{
.custom instance void [System.ServiceModel]
System.ServiceModel.ServiceContractAttribute::.ctor() = ( 01 00 00 00 )
Now you need to add the [OperationContract]
MSIL to your methods. Since they are interface methods, they'll be abstract - just a pair of curly braces. You need to add the attribute inside the curly braces.
.method public hidebysig newslot abstract virtual
instance class MyReturnType
MyMethod(valuetype [mscorlib]System.Guid inputId,
string inputData) cil managed
{
.custom instance void [System.ServiceModel]
System.ServiceModel.OperationContractAttribute::.ctor() = ( 01 00 00 00 )
}
Re-assembly
Once you've updated all the methods, it's time to recompile the assembly. If you haven't already, make a backup of your existing assembly just in case you break something. When you assemble the new file, you will need to remember to include the resource file if ildasm produced one.
Again, make sure you use the ilasm version that corresponds to the .NET version of your legacy assembly. Mine is .NET 1.1, so I'm using ilasm version 1.1.4322.2032. This will ensure that your assembly will still run under .NET 1.1 if necessary. The great thing about attributes is that if the executing code doesn't know about them, it just won't use them; you aren't going to break runtime compatibility.
ilasm /DLL <assembly>.il /resource=<assembly>.res
At this point you have the same .NET 1.1 compatible assembly, but your interface and methods are decorated with the attributes WCF will need when running under .NET 3.0. Take the updated interface assembly and the unchanged implementation assembly and rehost that legacy code in the robust and secure infrastructure provided by WCF!