I have an article available for publication for national audiences only. This means that the article should either be translated into a local language (anything but English), either distributed to a closed community (subscribers only).
If anyone is interested, please contact me. And if you want your favorite magazine to publish something about PostSharp, forward them this page :-D.
P.S. The article is great!
In my previous post I claimed that it was not possible, in general, to merge assemblies enhanced by PostSharp, because it would break the assembly references stored as strings in aspect serialization data.
I did not realize that the BinaryFormatter provides a way to solve our problem. It is indeed possible to provide its own SerializationBinder, whose role is precisely to return the System.Type corresponding to an assembly name and a type name. We can provide a custom binder to redirect merged assemblies.
This is the feature I have added to build 220.127.116.111 available for download in the builds section; I could still do it in 1.0 since it is a no-risk feature, breaking nothing existing (if you don't use it, nothing can go wrong).
I have added a new class PostSharp.Laos.LaosSerializationBinder. You can set the static property Current to your own implementation of SerializationBinder. If you don't set it, nothing is changed. The LaosSerializationBinder class it itself derived from SerializationBinder and implements the feature we need: assembly retargeting. So all you have to do is to create an instance of this class, set up retargeting policies, and assign it to LaosSerializationBinder.Current.
The following code sets up PostSharp Laos so that references to 'MergedPostSharpLib.dll' are retargeted to 'MergedPostSharp.exe' (supposing that the library has been merged into the executable):
LaosSerializationBinder binder = new LaosSerializationBinder();
LaosSerializationBinder.Current = binder;
The only thing you have to really take care about is to set up the binder before the first aspect is deserialized. Aspect deserialization is triggered from static constructors of enhanced classes, so you may need to initialize the weaver very soon, and eventually to refactor your "Main(string args)" method.
Apart from that, it should work very well.
Combining PostSharp with ILMerge seems a recurring demand. Indeed, many developers don't welcome the multiplication of dependent assemblies as PostSharp.Public.dll and PostSharp.Laos.dll, and ILMerge seems the dreamed solution to that. Unfortunately, it will work only in rare cases.
The Simple Case
Say you have an assembly named MyProgram.exe with aspects defined in this assembly. The application is formed of the following assemblies:
In this particular case, it is valid to merge all three assemblies into a new assembly equally named MyProgram.exe.
However, if you modify the name of the merged assembly, it will cease to work.
Remember that the aspects are serialized into the assembly. It uses the BinaryFormatter to do the job. Unfortunately for our purpose, this formatter stores the full type name of aspects, including the assembly name. So when you rename the assembly, you break the link between the aspect serialization and the underlying types, and you get an exception during deserialization.
The same occurs when you have aspects in one of the dependencies you merge. Say your program references MyLibrary.dll, whose some classes have been enhanced by PostSharp Laos. If you merge it into MyProgram.exe, the serialization of aspects previously defined in MyLibrary.dll will be broken.
The problem clearly lays in the use of the BinaryFormatter to do the job. We could eventually use another serializer that does not store the full type name.
This feature (pluggable serializers) was actually present in former builds of what is now PostSharp 1.5, but I have removed the feature because it became useless. If there is some interest, I could restore it. It very much depends on the feedback I will get.
How is this a critical feature for you?