views:

100

answers:

5

I have a situation where I would like to intercept calls to properties in .NET. I have been looking at DynamicProxy in Castle and it seems to work fine. But it seems in order to use it I have to start with a new object, meaning I can't do something like this:

MyType myType = new MyType();
myType.Property = "Test";

...

MyType wrappedMyType = proxyBuilder.Wrap(myType, new MyInterceptor());
wrappedMyType.Property = "Test2";

Am I just missing something?

EDIT:

Oh god, it should of course be wrappedMyType. Big mistake. Sorry. :(

+2  A: 

It doesn't work like that, it doesn't change the original object in any way.

Think of it like this. Let's consider moving to China, and working for a Chinese company, that will only pay your salary to a Chinese bank account in a Chinese bank.

So, you need to get a Chinese bank account. Problem is, that the bank you want to use, doesn't speak english, so you have a problem.

What you could do, if this was available, would be to call up a proxy service, a translator service, that on your behalf, calls the bank. Anything you say to this proxy person, will be translated to chinese, and said to the bank official. Anything he/she responds with in chinese will be translated back to english, and spoken to you.

In effect, you can now do something along the communication line when talking to your bank.

However, it does not make your bank officials speak english.

The proxy object, from your example, does not modify the underlying object. Whenever you call methods on your proxy objects, they will in turn call methods on the underlying object, possible doing processing along the way.

But if you sidestep the proxy object, nothing has changed.

Lasse V. Karlsen
+1 for the language/bank analogy :)
Jan
Sorry, made a mistake in my code example that completely changes the meaning of it. :(
Tobias Hertkorn
That's ok, but now I don't understand the question. Exactly what is it that you want, and what is it that isn't, or is, happening?
Lasse V. Karlsen
I am just wondering why no automatic proxy generator has this kind of feature. Sorry for not making it clear enough.
Tobias Hertkorn
I'm sorry, but the point I was trying to make in my previous comment is that I *do not understand your question*, hence "this kind of feature" is meaningless to me. What specifically is it that you want to do? Note, if you want your proxy interceptor to be called for all method calls on the underlying object, when a fitting method is called on the proxy object, it is entirely possible to do that, with the limitation that the proxy object can only handle virtual methods (or through an interface.)
Lasse V. Karlsen
A: 

You could get really, REALLY crazy with dynamic code generation and reflection, but I would honestly re-evaluate your needs before you even attempted looking in that direction (that way lies madness).

Bryan Ross
A: 

You could probably do this using the System.Reflection.Emit.TypeBuilder but it wouldn't be easy and probably wouldn't work on all types. For instance you couldn't do it on sealed types because in order to maintain the ability to use your type normally you would have to inherit from it in the type you build and you would have to either override or shadow every property on the base class. On top of that you would have to emit the IL into the body of the properties set methods when you override it to raise an event or something.

All of this is possible but not easy and not perfect. You would probably be better off with another solution. I do enjoy this kind of stuff though so maybe if I get some time I'll update this answer with a code sample (Sorry I'm supose to be "working").

Update: The more I think I about this it's not going to happen. Maybe if the objects you're trying to wrap always implement an interface and you only want to intercept those members. I thought about posting a sample for that but I think it would pollute this question. Best case scenario you would end up in the situation described in Jason's answer.

dukk
+1  A: 

You can't do this, and for good reasons. This is not specific to Castle Windsor. The issue is that you have no guarantee that the methods are marked as virtual and therefore you have an inconsistency where there is some state coming from the wrapped object and some state coming from the proxy object.

Think of the following very simple example:

abstract class AbstractPerson {
    public int Age { get; protected set; }
    public abstract void Birthday();
}

class Person : AbstractPerson {
    public Person(int age) { Age = age; }
    public override Birthday() { Age++; }
}

Let's say that we want to create a proxy for AbstractPerson to intercept Birthday.

class PersonProxy : AbstractPerson {
    readonly AbstractPerson wrappedPerson;

    public PersonProxy(AbstractPerson person) { 
        wrappedPerson = person;
    }
    public override void Birthday() {
        DoInterceptors();
        wrappedPerson.Birthday();
    }
    public void DoInterceptors() { 
        // do interceptors 
    }
}

Notice that we can't override Age because it's not marked as virtual. This is where the yucky state inconsistencies will come from:

Person knuth = new Person(71);
PersonProxy proxy = new PersonProxy(knuth);
Console.WriteLine(knuth.Age);
knuth.Birthday();
Console.WriteLine(knuth.Age);
Console.WriteLine(proxy.Age);

This will print

71
72
0

to the console. What happened? Because Age is not marked as virtual, our proxy object can't override the base behavior and call wrappedPerson.Age. This example even shows that adding Age = wrappedPerson.Age to the constructor for PersonProxy will not help. Our proxy isn't really a proxy. This is why you can not wrap existing objects.

Jason
Doesn't your example cater to a subset of existing objects? Why not reject proxying objects that fit your example and allow proxying for all other cases?
Tobias Hertkorn
A: 

PostSharp may be usable for you, depending on exactly what you want to do with the "interception", and if you can modify the original code.

For this to be a viable option you must be able to add attributes to the original properties that you want to intercept. (I'm guessing this is not an option in your case, but can't tell for sure.) If you are able to do this, you can create an attribute (derived from OnMethodBoundaryAspect) which can both set the 'ReturnValue' and 'FlowBehavior' such that you've effectively intercepted the call.