Castle Dynamic Proxy tutorial part XIV: Persisting proxies

This is part four­teen of my tuto­r­ial on Cas­tle Dynamic Proxy.

Wow, what I had planned as few parts tuto­r­ial has turned to noth­ing less than full exam­i­na­tion of Dynamic Proxy capa­bil­i­ties. Of all most impor­tant fea­tures we' have basi­cally just one left – proxy per­sis­tence, which is what we’re going to talk about today.

Dis­cus­sion

Although Dynamic Proxy’s name sug­gests that it’s use­ful for… well cre­at­ing prox­ies on the fly at run­time, there are other sce­nar­ios where the frame­work can be use­ful. We’ve seen one such sce­nario last time, when we cre­ated mix­ins, not using prox­y­ing at all.

Also the dynamic aspect of prox­ies is not always what we want. This is not so appar­ent in server appli­ca­tion where appli­ca­tion starts once and runs (hope­fully) for a long time with­out restart. In the desk­top appli­ca­tions how­ever, we might find our­selves cre­at­ing lots of iden­ti­cal prox­ies over and over again each and every time user starts the application.

This may degrade the per­cep­tion of the appli­ca­tion from users per­spec­tive, 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 man­i­fests itself by non­lin­early increas­ing time that cre­at­ing of each sub­se­quent proxy type takes (Mono appar­ently does not have this issue. I cre­ated a Con­nect ticket for it here. Please vote on the issue).

In some sce­nar­ios using sta­tic weaver like Post­Sharp will be suf­fi­cient. How­ever it is not an option if the shape of your prox­ies depends on some dynamic aspects of user envi­ron­ment, con­fig­u­ra­tion etc. In this case you may not know which prox­ies and how shaped until your soft­ware is on the users machine.

Let’s say you cre­ated a WPF appli­ca­tion that allows its GUI to be extended with third party exten­sions, and that you use Dynamic Proxy to dynam­i­cally cre­ate View­Mod­els and INo­ti­fyProp­er­ty­Change on top of your POCO mod­els. Clearly using sta­tic weaver is not an option here, because if would defy the whole point of dynamic extensibility.

How­ever once an exten­sion is installed, it’s really no point in recre­at­ing prox­ies for mod­els in it over and over again. Ide­ally you would want to cre­ate them once, the first time you load the exten­sion, and then reuse them… at least until user installs updated ver­sion of the extension.

Good news is, (as you prob­a­bly sus­pected any­way) it is pos­si­ble using Dynamic Proxy. There’s no sup­port for deter­min­ing whether or not you should reuse exist­ing prox­ies, but this is very sce­nario spe­cific so hav­ing any code for this in the frame­work itself wouldn’t make much sense any­way. Let’s look at the code.

Let’s see some code

So far we’ve been cre­at­ing Prox­y­Gen­er­a­tor instances using default constructor.

var generator = new ProxyGenerator();

If we want to per­sist our prox­ies, 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 cre­ate Mod­ule­Scope our­selves (which we’ll later use to save the assem­bly to disk) pass­ing true, as first argu­ment, to tell Dynam­icProxy that we want to per­sist the assem­bly with gen­er­ated types. If we didn’t do it, we would get an excep­tion if we tried to save the assem­bly. We then pass two pairs of assemblyname/filename — strongly named and weakly named ver­sion. If you intend to use just one (like in this exam­ple I’m going to only save weakly named assem­bly) you can pass the default val­ues for strongly typed ver­sion defined as con­stants on Mod­ule­Scope type.

Save me, Save me

That was the first part of the task. We then use the gen­er­a­tor to cre­ate the proxy types we need, and when we’re done (most likely upon clos­ing the pro­gram) we use scope to save the assembly.

scope.SaveAssembly(false);

The argu­ment value of false means that we want to save the assem­bly with­out strong name.

generatedProxyAssembly

And after the call the assem­bly lands safely in the des­ig­nated folder under the name pro­vided in the con­struc­tor. You can now fire up Reflec­tor and see the inner work­ings of proxy types if that’s what you want.

reflector

One small catch – remem­ber that you only can call save once on a mod­ule scope. If you don’t Dynamic Proxy will remind you:

assemblySaveTwiceError

Let’s get it back

We now have just one ele­ment miss­ing, that is load­ing saved types. As I said find­ing the assem­bly itself is your respon­si­bil­ity. When you do, and decide to use it, you do it like this:

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

The Load­Assem­bly­In­to­Cache method will look for proxy types in the assem­bly and add all it finds to the cache, so that the next time proxy gen­er­a­tor asks for type match­ing one of cached one, that type will be used, instead of cre­at­ing a new one.

Two things to note here:

You can load more than one assem­bly into the mod­ule scope’ cache (dupli­cates will be overriden).

You can save the dynamic assem­bly even after you’ve loaded types from other assem­blies to its scope. Note that only types gen­er­ated in this new assem­bly will be saved, not the ones loaded from other assem­blies (which is pretty logical).

If you want to check before sav­ing if any new types were gen­er­ated, you can use the fol­low­ing piece of code:

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

Wrap­ping up

That would basi­cally be it. We pretty much cov­ered every aspect of the frame­work, and hope­fully by now you have pretty good under­stand­ing of what and how you can achieve with it. If you think there’s some­thing miss­ing, or you’d like me to talk more about cer­tain top­ics I already touched let me know in the comments.

Tech­no­rati Tags: ,
  • Roland

    Absolutely fan­tas­tic series on DP. This most com­pre­hen­sive and coher­ent tuto­r­ial I have come across. I have passed the link to my col­leagues as a must read tutorial.

    I so wish dp could have some time shift­ing func­tion­al­ity so that I could have read the series when I was learn­ing DP a cou­ple years back — it would have saved me weeks of headache.

    I won­der how I ever man­aged to design and code with­out DP and Wind­sor. These con­cepts are so pow­er­ful that when I took over the archi­tec­ture of an exist­ing ui plug-in frame­work project we man­aged to com­pletely rewrite the code, imple­ment new require­ments, elim­i­nate old bugs and still deliver ahead of sched­ule with no errors.

    Long live cas­tle — the best of the best.

  • Per Lund­berg

    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 gen­er­ated Type from a call to the Cre­ate­ClassProxy() method. Can it be done? If so, how?

    (what I mean is that I would then use Activator.CreateInstance() to cre­ate a new instance of it, rather than hav­ing to call Cre­ate­ClassProxy over and over again, since pro­fil­ing has shown me that this method is quite heavy)

    Thanks in advance for any answer to this.

    Best regards,
    Per

  • http://kozmic.pl/Default.aspx Krzysztof Koźmic

    @Per,

    I believe the issue is set­tled here: groups.google.com/…/4d1d294513d483fa

    and for the record — DP does cache proxy types so you take the hit of gen­er­at­ing the proxy type just once if you let caching do its job: kozmic.pl/…/…xy-tutorial-part-xii-caching.aspx