ViewModel with Castle Windsor interceptor

Jul 8, 2011 at 2:47 PM

Hi at all,
I've a question :)

I need to wrap some viewmodel methods with a user control code (eg. check if the current user can execute that methods). I decided to achive this using a Castle Windsor interceptor but unfortunately Windsor wraps the whole class with a dynamically generated proxy class but this breaks the CM view locator mechanism.

I solved this problem using some view model helpers with the methods that i need to control and applying the interceptor to this classes.

Is there a best way to solve the problem?

Coordinator
Jul 8, 2011 at 2:59 PM

What you should do is override replace ViewLocator.LocateTypeForModelType. Your new func should determine the underlying type of your proxy, pass that to the original LocateTypeForModelType func and then return the value. You set this up in your bootstrapper's configure method. It would be something like this:

var original = ViewLocator.LocateTypeForType;
ViewLocator.LocateTypeForType = (modelType, displayLocation, context) =>{
   var significantModelType = //determine if modelType is a proxy; if so, get underlying type
   return original(significantModelType, displayLocation, context);
};

Jul 16, 2011 at 6:20 PM

I've overridden that function and now I can determinate correctly the actual type of the model but for some reason when i wrap a model with a proxy this doesn't work well, for example if I wrap a Conductor<IScreen>.Collection.OneActive based class I can't activate item and if i wrap an IScreen class (without wrapping the conductor) I can't deactivate that item. Debugging the project I've noticed that in the framework classes the this keyword refers to the wrapped class not to the proxy (eg. if i wrap the ShellViewModel the this refers to the ShellViewModel and not to the Proxy genereted)... 

Jul 17, 2011 at 12:37 AM

May it have to do with the kind of proxy you are using?
For example, DynamicProxy's CreateInterfaceProxyWithTarget method creates a proxy that (under interceptors control) delegates invocations to a private instance of the class being proxied.
In this scenario, if you step into the proxied class' code with the debugger, you are actually observing the private instance running, while the caller sees the proxy instance.

You may want to have a look at this excellent DynamicProxy tutorial http://kozmic.pl/dynamic-proxy-tutorial/ (written by Krzysztof Koźmic), which explains in depth the various kind of proxies along their characteristics.

Also, feel free to post some part of your code in order to let me to verify my guess. 

 

Jul 17, 2011 at 11:38 AM
Edited Jul 17, 2011 at 11:59 AM

This is how I register the shell view model and the interceptor:

 

Component.For<IShell>().
ImplementedBy<ShellViewModel>().
Interceptors(InterceptorReference.ForType(typeof(UserElevationAttemptInterceptor))).Anywhere.
LifeStyle.Is(LifestyleType.Singleton)

 

The UserElevationAttemptInterceptor is a trivial interceptor that simply call the intercepted methods with invocation.Proceed();
I don't know in this way what kind of proxy is generated 

I'm new to the dynamic proxy :)

P.S.
I'm reading the Krzysztof DP tutorial, it's very well done but a bit dated

EDIT
Ok I don't know why but if I register the concrete type instead of the interface ( Component.For<ShellViewModel>().Implemented ecc... ) all works gracefully.
I really need a better understandig of the CW DynamicProxy

Jul 17, 2011 at 8:03 PM

I believe the erroneous behavior is caused by an incomplete proxying of all the interfaces of CM's Application Model classes, or by the kind of proxy created by Windsor (it's hard to figure out without knowing the exact issue).
I suggest you to experiment the various DP creation options in isolation, using DP without the container. Once you get this test squared, you can try to integrate with Windsor, too.