Castle Dynamic Proxy tutorial part XIV: Persisting proxies

This is part fourteen of my tutorial on Castle Dynamic Proxy.

Wow, what I had planned as few parts tutorial has turned to nothing less than full examination of Dynamic Proxy capabilities. Of all most important features we’ have basically just one left – proxy persistence, which is what we’re going to talk about today.

Discussion

Although Dynamic Proxy’s name suggests that it’s useful for… well creating proxies on the fly at runtime, there are other scenarios where the framework can be useful. We’ve seen one such scenario last time, when we created mixins, not using proxying at all.

Also the dynamic aspect of proxies is not always what we want. This is not so apparent in server application where application starts once and runs (hopefully) for a long time without restart. In the desktop applications however, we might find ourselves creating lots of identical proxies over and over again each and every time user starts the application.

This may degrade the perception of the application from users perspective, because it will take a lot of time to start. When you have many proxy types, things may get quite bad, due to bug in BCL. I call it a bug but it manifests itself by nonlinearly increasing time that creating of each subsequent proxy type takes (Mono apparently does not have this issue. I created a Connect ticket for it here. Please vote on the issue).

In some scenarios using static weaver like PostSharp will be sufficient. However it is not an option if the shape of your proxies depends on some dynamic aspects of user environment, configuration etc. In this case you may not know which proxies and how shaped until your software is on the users machine.

Let’s say you created a WPF application that allows its GUI to be extended with third party extensions, and that you use Dynamic Proxy to dynamically create ViewModels and INotifyPropertyChange on top of your POCO models. Clearly using static weaver is not an option here, because if would defy the whole point of dynamic extensibility.

However once an extension is installed, it’s really no point in recreating proxies for models in it over and over again. Ideally you would want to create them once, the first time you load the extension, and then reuse them… at least until user installs updated version of the extension.

Good news is, (as you probably suspected anyway) it is possible using Dynamic Proxy. There’s no support for determining whether or not you should reuse existing proxies, but this is very scenario specific so having any code for this in the framework itself wouldn’t make much sense anyway. Let’s look at the code.

Let’s see some code

So far we’ve been creating ProxyGenerator instances using default constructor.

var generator = new ProxyGenerator();

If we want to persist our proxies, we have to write more code:

var savePhysicalAssembly = true;
var strongAssemblyName = ModuleScope.DEFAULT_ASSEMBLY_NAME;
var strongModulePath = ModuleScope.DEFAULT_FILE_NAME;
var weakAssemblyName = "Foo.Bar.Proxies";
var weakModulePath = "Foo.Bar.Proxies.dll";
var scope = new ModuleScope(savePhysicalAssembly, strongAssemblyName, strongModulePath, weakAssemblyName, weakModulePath);
var builder = new DefaultProxyBuilder(scope);
var generator = new ProxyGenerator(builder);

We have to create ModuleScope ourselves (which we’ll later use to save the assembly to disk) passing true, as first argument, to tell DynamicProxy that we want to persist the assembly with generated types. If we didn’t do it, we would get an exception if we tried to save the assembly. We then pass two pairs of assemblyname/filename – strongly named and weakly named version. If you intend to use just one (like in this example I’m going to only save weakly named assembly) you can pass the default values for strongly typed version defined as constants on ModuleScope type.

Save me, Save me

That was the first part of the task. We then use the generator to create the proxy types we need, and when we’re done (most likely upon closing the program) we use scope to save the assembly.

scope.SaveAssembly(false);

The argument value of false means that we want to save the assembly without strong name.

generatedProxyAssembly

And after the call the assembly lands safely in the designated folder under the name provided in the constructor. You can now fire up Reflector and see the inner workings of proxy types if that’s what you want.

reflector

One small catch – remember that you only can call save once on a module scope. If you don’t Dynamic Proxy will remind you:

assemblySaveTwiceError

Let’s get it back

We now have just one element missing, that is loading saved types. As I said finding the assembly itself is your responsibility. When you do, and decide to use it, you do it like this:

Assembly proxyAssembly = GetProxyAssembly();
scope.LoadAssemblyIntoCache(proxyAssembly);

The LoadAssemblyIntoCache method will look for proxy types in the assembly and add all it finds to the cache, so that the next time proxy generator asks for type matching one of cached one, that type will be used, instead of creating a new one.

Two things to note here:

You can load more than one assembly into the module scope’ cache (duplicates will be overriden).

You can save the dynamic assembly even after you’ve loaded types from other assemblies to its scope. Note that only types generated in this new assembly will be saved, not the ones loaded from other assemblies (which is pretty logical).

If you want to check before saving if any new types were generated, you can use the following piece of code:

Type[] types = scope.ObtainDynamicModuleWithWeakName().GetTypes();
if(types.Length>0)
{
    //there are new types.
}

Wrapping up

That would basically be it. We pretty much covered every aspect of the framework, and hopefully by now you have pretty good understanding of what and how you can achieve with it. If you think there’s something missing, or you’d like me to talk more about certain topics I already touched let me know in the comments.

Technorati Tags: ,

3 Thoughts.

  1. Absolutely fantastic series on DP. This most comprehensive and coherent tutorial I have come across. I have passed the link to my colleagues as a must read tutorial.

    I so wish dp could have some time shifting functionality so that I could have read the series when I was learning DP a couple years back – it would have saved me weeks of headache.

    I wonder how I ever managed to design and code without DP and Windsor. These concepts are so powerful that when I took over the architecture of an existing ui plug-in framework project we managed to completely rewrite the code, implement new requirements, eliminate old bugs and still deliver ahead of schedule with no errors.

    Long live castle – the best of the best.

  2. Thanks for the post, Krzysztof! This is *almost* what I want to do, but not quite. What I’d like to do is to be able to "cache" the generated Type from a call to the CreateClassProxy() method. Can it be done? If so, how?

    (what I mean is that I would then use Activator.CreateInstance() to create a new instance of it, rather than having to call CreateClassProxy over and over again, since profiling has shown me that this method is quite heavy)

    Thanks in advance for any answer to this.

    Best regards,
    Per

Comments are closed.