5

I'm using Castle-Windsor as my container in a Caliburn-Micro Silverlight app. My ViewModel objects are reasonably chunky as they call WCF services and a bunch of other stuff. Therefore, when a window is closed I want to call container.Release(viewModel) so Castle can manage the whole decommission/disposal process, respecting the various lifecycles configured (as outlined in this post).

In my AppBootstrapper I have overridden GetInstance as follows:

protected override object GetInstance(Type serviceType, string key)
{
    if (string.IsNullOrEmpty(key)) return container.Resolve(serviceType);
    return container.Resolve(key, serviceType);
}

But I am struggling to come up with a clean/elegant way of calling container.Release(viewModel). There don't seem to be any hooks available for this.

What is the simplest way of releasing ViewModel objects returned from ViewModelLocator in a Caliburn Micro app?

Phil Degenhardt
  • 7,215
  • 3
  • 35
  • 46

1 Answers1

0

The lifecycle you want for each of your VM types is going to have an impact here, so there is not really a right answer for the context you have provided.

The Screen base class of CM provides you with protected virtual void OnDeactivate(bool close); which is a good place to start. For your heavyweight VMs you should override this method, and if the VM is closing indicated by the close parameter, release any resources (WCF channels etc) that need to be disposed of, this would include disposing the resource (if IDisposable is relevant) and also disconnecting any references to it so that it can be cleaned up by the GC.

I don't use Castle so I can't help you in terms of configuring lifecycles etc. But if you follow the above, you aren't going to be holding on to anything heavy weight. I assume that with the correct lifecycle configuration, Castle will clean up any old instances that you aren't going to use again itself without an explicit call to Release.

Simon Fox
  • 10,409
  • 7
  • 60
  • 81
  • Thanks very much @Simon. I'd been exploring the OnDeactivate route as a place to hook. Yes if you have a VM with a long constructor parameter list, Castle will satisfy all the dependencies of that component's constructor. Then when the component is Release()d Castle will release all the dependencies, according to the lifestyles configured for each of them. The important thing here is that the Vms themselves are not responsible for any of the cleanup work - it is all automatic. – Phil Degenhardt Mar 15 '12 at 22:02
  • Pushing responsibility down to the VMs themselves could work but it means the VMs start to get polluted with lifecycle responsibilities which I really want to keep out of them if possible. Ideally responsibility for Release should live with responsibility for Resolve - i.e. higher up the call stack, in the bootstrapper or at the container itself... – Phil Degenhardt Mar 15 '12 at 22:06
  • Yeah thats sort of what I am saying, as an example if you configured your VM type with a lifecycle of "single use" (what ever that maps to in Castle) then next time you request an instance of that type, the container should just release the used instance because it has already been used....no explicit call to release required. – Simon Fox Mar 15 '12 at 22:09
  • Based on your example of WCF Services, your VM might have a factory abstraction for creating WCF channels in its parameter list. Castle will inject that factory for you, but something like that should have a longer lifetime and you shouldn't need to release it. As long as you dispose and disconnect any channels you have created via that factory in OnDeactivate, you should be good. Make sense? – Simon Fox Mar 15 '12 at 22:11
  • Thanks @Simon. For the pattern to work reliably we need to ensure a Release() is paired with every Resolve() - that way the container can ensure proper decommissioning of the component according to the configured lifecycle. This applies even if the component is 'transient' (Castle speak for single use). With the example you raise of the WCF service, I simply want my VM to declare a constructor requirement for say, ISomeService. The VM should not require any knowledge of it's own lifecycle or that of ISomeService. – Phil Degenhardt Mar 16 '12 at 03:49
  • If we setup our VMs so some of them call Release() and others do not, then we are implicitly embedding knowledge of their own lifecycle within them and it will quickly become a nightmare to configure the container... – Phil Degenhardt Mar 16 '12 at 03:50
  • Must be missing something. Does Castle really require an explicit Release call for a transient type? Once the initial resolution is complete I would expect the instance to be released if its life cycle is set to transient. – Simon Fox Mar 16 '12 at 03:53
  • I totally agree, and am not suggesting you call Release from the VM. I just don't see why the container would hold on to a transient instance (this is probably just my lack of Castle experience), once it has been built up, the container should be able to forget about it. As I mentioned, something like a factory for services can stay in the container and be reused and you shouldn't have to release that until the application closes (which you can hook from your bootstrapper). – Simon Fox Mar 16 '12 at 03:59
  • I prefer not to inject services directly when talking Silverlight, because you can't make use of things like HTTP request scoped lifecycles. Instead, injecting a factory in to my VM which can create services, and at the same time can sit around in the container for the duration of the applications life because it is lightweight. – Simon Fox Mar 16 '12 at 04:03
  • yeah there's a bit of controversy about Castle holding references to transients (see the article link in my question for further info). Interesting point about the request scoped lifecycles. – Phil Degenhardt Mar 16 '12 at 05:06