Using ProxyFactory

7 views
Skip to first unread message

Pascal Craponne

unread,
Aug 4, 2008, 7:55:47 AM8/4/08
to linfufr...@googlegroups.com
Hi everyone,

new to LinFu (and kinda like it), I'm doing some tests with the ProxyFactory.
At this time, I'm having problems on intercepting calls to simple classes.

I have a simple class with an interceptor. This class contains one virtual method. The interceptor works fine, since it intercepts the call to my method, but the interceptor, when trying to pass call to original method calls itself again, and enters an infinite loop.

I join the test .cs file, it is very simple to understand (well... I hope so :)).

Can someone give me a hand?

--
Pascal.

jabber/gtalk: pas...@jabber.fr
msn: pas...@craponne.org

Program.cs

Philip_L

unread,
Aug 4, 2008, 8:35:27 AM8/4/08
to LinFu.Framework
Hi Pascal,

You're getting an infinite loop because you're calling the target
method with the proxy itself as the target. When you make a call to
TargetMethod.Invoke, you need to make sure that the target that your
using isn't the proxy itself. I hope that helps. :)
> [Program.cs]using LinFu.DynamicProxy;
>
> namespace LinFuFanApplication
> {
>     public class Adder
>     {
>         public virtual int Add2(int a)
>         {
>             return a + 2;
>         }
>     }
>
>     public class DummyInterceptor : IInterceptor
>     {
>         public object Intercept(InvocationInfo info)
>         {
>             // I have an infinite loop, here, how to avoid it?
>             return info.TargetMethod.Invoke(info.Target, info.Arguments);
>         }
>     }
>
>     class Program
>     {
>         static void Main(string[] args)
>         {
>             var proxyFactory = new ProxyFactory();
>             var a = proxyFactory.CreateProxy<Adder>(new DummyInterceptor());
>             var c = a.Add2(2);
>         }
>     }
>
> }

Pascal Craponne

unread,
Aug 4, 2008, 9:00:28 AM8/4/08
to linfufr...@googlegroups.com
Hi Philip,

thanks for fast answer. However, my problem is still here: if I have a class (not an interface) with members and methods, and I want to intercept methods in my class without changing the target (target == proxy intercepted), otherwise I will lose some information (present in proxy, not target).

Pascal.

Philip_L

unread,
Aug 4, 2008, 9:18:02 AM8/4/08
to LinFu.Framework
Hi Pascal,

You don't need to change the target at all. In fact, you're getting a
loop because the call to:

TargetMethod.Invoke(info.Target, info.Arguments);

...is causing the proxy to infinitely call itself. The proxy will
never be able to call the actual object since the DummyInterceptor
doesn't actually have an actual Adder instance that it can use to
delegate the actual call.

Try this version of the DummyInterceptor instead:

namespace LinFuFanApplication
{
public class Adder
{
public virtual int Add2(int a)
{
return a + 2;
}
}

public class DummyInterceptor : IInterceptor
{
private object _actualObject;
public DummyInterceptor(object actualObject)
{
_actualObject = actualObject;
}
public object Intercept(InvocationInfo info)
{
// Add my own custom code to the interception process
Console.WriteLine("'{0}' method called",
info.TargetMethod.Name);

// Call the actual Adder object instance instead of the
proxy;
// this will solve your looping problem
return info.TargetMethod.Invoke(_actualObject,
info.Arguments);
}
}

class Program
{
static void Main(string[] args)
{
var proxyFactory = new ProxyFactory();
var a = proxyFactory.CreateProxy<Adder>(new
DummyInterceptor(new Adder()));
var c = a.Add2(2);
}
}

..and that should do it. Go ahead and give it a try, and let me know
if it works. :)

Pascal Craponne

unread,
Aug 4, 2008, 10:18:42 AM8/4/08
to linfufr...@googlegroups.com
I know your solution works, because I also use it under other circumstances (typically, a proxy behind an interface), but here, it's not the same thing. I try to explain a bit deeper:
Let's assume my class Adder has a field. If I use a proxy, I will get two objects, the original being my proxy, and a target.
If I change the field in my user instance (the proxy), then the called method (in the target) will use its field, the one that wasn't modified.
So today, the proxy is unusable for anything else than an interface. For information, Castle Project allows this kind of manipulation (but has other limitations, this is why I'm trying LinFu).

I'm going to see if I can do something for this problem (I need to check if I can call the previous method with a delegate).

Pascal Craponne

unread,
Aug 4, 2008, 11:14:34 AM8/4/08
to linfufr...@googlegroups.com
Apparently, something can be done using the "call" instead of "callvirt" IL instruction. The idea would then be to generate some alternative methods in the proxy, and get a MethodInfo to each one, related to the original call. After this, the proxy would just call this special method, then calling non virtually the original method.

Hope I'm clear :)

Pascal Craponne

unread,
Aug 4, 2008, 4:42:40 PM8/4/08
to linfufr...@googlegroups.com
Hi Philip,

I attached a patch here to call original method in the special case of a class without target (being the target itself). Thanks to LinFu structure, the implementation was easy (yes, flattery is free [as in speech] tonight :)).
The original method can be called from a method in InvocationInfo named Proceed(). (I had no better idea).
The trick is done by creating some extra methods in the proxy (ending in " Original"), and the InvocationInfo finds them from a given proxied MethodInfo and invokes them. It is a trick, and there are things I don't like in what I did (all code is commented and contains a lot of // TODO), but basically it works.

It allows me to carry on my own development (if you allow me, I'll advertise on it when it's more mature).

The patch works on latest SVN revision (in trunk).

Pascal.
OriginalMethodCall.zip

Philip Laureano

unread,
Aug 4, 2008, 5:36:46 PM8/4/08
to linfufr...@googlegroups.com
Hi Pascal,

If you allow users to call the original method using OpCodes.Call against the proxy, that implies that you'll be allowing the proxy to maintain state as if it were a real object, instead of forwarding the call to an interceptor. The proxy is designed to hold absolutely no state (other than the IInterceptor field), and every virtual call made to that proxy is designed to be forwarded to the interceptor.

The reason why this works with Castle's proxy is that their proxies are actually both call forwarding proxies and actual objects that can hold state of their own (presumably because Castle adds constructors to the proxy which initialize the proxy as if it were a real object). LinFu's proxy, in contrast, is built only to forward all its calls back to an interceptor. It certainly does have its limitations, but I've never had any problems proxying classes instead of interfaces.

Perhaps I'm missing something here--if you can show me another scenario where class-based interception fails and there's no workaround for it, then I'll be glad to add the patch to LinFu's DynamicProxy. I have to be very cautious about adding changes to LinFu's DynamicProxy. I could easily disable a large chunk of LinFu's functionality if its DynamicProxy breaks, so there has to be very strong justification for making changes to this one particular library.

Pascal Craponne

unread,
Aug 4, 2008, 6:05:12 PM8/4/08
to linfufr...@googlegroups.com
You're right, and I need to clarify two different concepts:

1. The first one, is a well known design pattern named "Proxy" (http://en.wikipedia.org/wiki/Proxy_design_pattern)
   - It has no state
   - It runs on interfaces
   - This is what LinFu allows to do in a transparent way
   - A typical use is when you need to dynamically change the target (I've been using it to hold WCF channels and expose the services to client in a stateless way, for example).

2. The second one, which I'm interested in implementing, is related to an AOP Advice (http://en.wikipedia.org/wiki/Aspect-oriented_programming)
   - It allows to run some code around method calls
   - It is not designed to change target, but to treat some transverse aspects.
   - It runs on instances (classes), with or without interface
   - This part is currently missing from LinFu, and can be added with a very few modifications (like I did)
   - Some uses are: database connection/transaction management in services, performance measurement, and so on.

My patch is probably not the best in terms of implementation:
- The generated methods are public
- There is a dirty constant shared between the IL generator and the InvocationInfo
- The cache is not moduler
- I'm probably not in LinFu's coding style and spirit.
But it doesn't break anything since it adds methods on generated proxy (if the proxy is on a class and if the method is not abstract) and just adds a method on InvocationInfo to find and invoke such methods.

Pascal.

Philip Laureano

unread,
Aug 4, 2008, 6:13:55 PM8/4/08
to linfufr...@googlegroups.com
Hi Pascal,

If you want to apply an AOP advice, you might want to check out LinFu.AOP. It allows you to do dynamic method interception/replacement without having to use any proxies. Hopefully that should help you add some AOP functionality to your applications. HTH :)

Pascal Craponne

unread,
Aug 4, 2008, 6:55:04 PM8/4/08
to linfufr...@googlegroups.com
Does it require a custom build? Apparently there is a special MSBuild task to "weave" the assemblies, how does it work with signed assemblies?

Thanks for you patience :)

Philip Laureano

unread,
Aug 4, 2008, 7:26:53 PM8/4/08
to linfufr...@googlegroups.com
You have to run either a command line tool (PostWeaver.exe) or the custom MSBuild task in order to inject the pointcuts into your assemblies. As for signed assemblies--it will only work if you strip the strong name and then patch the target assembly with LinFu.AOP.
Reply all
Reply to author
Forward
0 new messages