Using PostSharp At Runtime

by Gael Fraiteur on 29 Aug 2008

Users often ask if it is possible to use PostSharp at runtime, so aspects don't have to be known at compile time. Changing aspects after deployment is indeed a great advantage, since it allow support staff to enable/disable tracing or performance monitoring for individual parts of the software. One of the cool things it would enable is to apply aspects on third-party assemblies.

If you ask whether it is possible, the short answer is yes! Unfortunately, the long answer is more complex.

Theoretically, it should be possible to transform assemblies before they are loaded by the CLR. The idea is to develop a kind of bootstrapper, or host, that transforms all relevant assemblies before the CLR need them. PostSharp has been designed to be used with such bootstrappers. So you can perfectly invoke PostSharp from your application. The most typical scenario is when you develop an extensible application that loads "user assemblies", like an application server may load user applications, or like any other application may load plug-in. Basically, in this scenario, your application is the master, and user code the slave. The master can define rules slaves should follow; slaves are only partially trusted and some code should be transformed. For instance, in an application server providing persistence, persistent objects of user applications will be transformed so that fields are transformed to database slots, and accesses to fields to accessed to these slots.

So when your code is in charge and can impose a fairly large set of restrictions on transformed assemblies, it is technically feasible to host PostSharp. There is a special hosting API for this purpose. PostSharp comes with two build-time hosts: the MSBuild task the command-line utility. It also comes with a sample demonstrating how to make a runtime host; this sample transforms all assemblies in the closure of the entry assembly.

So now, what are the gotchas?

  • Plugging the bootstrapper. If your code is hosted (for instance in ASP.NET or in a COM server), you cannot plug the bootstrapper. So any runtime weaving technology is bound to the limitation that you should host the application yourself.
  • Be Before the CLR. If the CLR finds the untransformed assembly by its own, it will not ask for the transformed one. So you may need to create a new application domain for the transformed application, and put transformed assemblies in its binary path. It's maybe not a big problem.
  • Strong names. Ough. If you modify an assembly at runtime, you will have to remove its strong name. Will it work? Yes, mostly. Of course, you have to remove the strong names from all references to this assembly. That's not a problem; PostSharp supports it out-of-the-box. But there is something PostSharp cannot help with: if there are some strongly named references in strings or files (for instance in app.config), we can hardly find them and transform them. So here we have a real limitation: there cannot be "loose references" to strongly named assemblies: we are only able to transform real references.
  • LoadFrom: If any assembly uses Assembly.LoadFrom, Assembly.LoadFile or Assembly.LoadBytes, our bootstrapper is skipped...

There may be a lot of circumstances in which these limitations don't matter. However, they are a sufficient reason not to develop an all-purpose bootstrapper. In other words, there is no one-size-fits-all bootstrapper.

Real CLR geeks know that the CLR itself can be hosted and its assembly loading mechanism can be customized. Couldn't it be used to transformed assemblies on the fly? Yes, but it would not help that much, because:

  • We still have to host the application ourselves.
  • This time we don't have to be before the CLR; we can do it on-the-fly.

  • We still have to remove strong names. Unfortunately, we cannot kindly ask the CLR to ignore strong names for the assembly we provide.

  • If we customize the assembly loading mechanism, we simply disable Assembly.LoadFrom, Assembly.LoadFile, Assembly.LoadBytes. So no JIT-emitted serializers, no compiled regular expressions, ...

So in a few words: if you are developing anything that looks like an application server, runtime PostSharp is for you. Otherwise, it's better you forget about it and read about specific runtime technologies like the profiling API.

Happy PostSharping anyway!