PDA

View Full Version : explicit interface proxy


a701440
07-25-2007, 04:44 PM
Hello,

We are trying to proxy a class that implements two explicit interfaces
with the same method names and signatures.

class A : IOne, ITwo
{
void IOne.Method()
{
}

void ITwo.Method()
{
}
}

It looks like that the calls that are coming in on one of the interfaces
are being directed to the implementation methods from another interface.

In the example above the call to the void Method() is made on the proxy for the IOne interface, but the actual method invoked is void ITwo.Method().

Are we missing anything or is this a bug ?

Bruno Baia
07-26-2007, 12:15 PM
Hi,

I'm not able to reproduce it.
I've created a new test cass and the test passes.

// http://forum.springframework.net/showthread.php?t=3248
[Test]
public void ExplicitInterfaceProxyWithSameMethodNamesAndSignat ures()
{
TheCommand target = new TheCommand();

AdvisedSupport advised = new AdvisedSupport();
advised.Target = target;
advised.AddAdvice(new NopInterceptor());

object proxy = CreateProxy(advised);

IServiceCommand serviceCommand = proxy as IServiceCommand;
Assert.IsNotNull(serviceCommand);
serviceCommand.Execute();

IBusinessCommand businessCommand = proxy as IBusinessCommand;
Assert.IsNotNull(businessCommand);
businessCommand.Execute();

Assert.AreEqual(1, serviceCommand.ServiceCount);
Assert.AreEqual(1, businessCommand.BusinessCount);
}

public interface IServiceCommand
{
int ServiceCount { get; }

void Execute();
}

public interface IBusinessCommand
{
int BusinessCount { get; }

void Execute();
}

public class TheCommand : IServiceCommand, IBusinessCommand
{
#region IServiceCommand Members

private int _serviceCount = 0;
int IServiceCommand.ServiceCount
{
get { return _serviceCount; }
}

void IServiceCommand.Execute()
{
_serviceCount++;
}

#endregion

#region IBusinessCommand Members

private int _businessCount = 0;
int IBusinessCommand.BusinessCount
{
get { return _businessCount; }
}

void IBusinessCommand.Execute()
{
_businessCount++;
}

#endregion
}


Be sure you cast the proxy to the appropriate interface before to call the method.


Bruno

a701440
07-26-2007, 04:39 PM
I am not sure if that matters, but I have a sequence of 2-3 around interceptors there before the control will reach the implementation class. I wonder if the mix-up happens when going from one proxy to another proxy.
I will try to put together a sample with the app context. I can definitely observe that effect.

a701440
07-26-2007, 07:13 PM
I have put together a sample that demonstrates the problem:

using System;
using System.Collections.Generic;
using System.Text;

using Spring.Context;
using Spring.Context.Support;
using AopAlliance.Intercept;

namespace ProxyTest
{
class Program
{
static void Main(string[] args)
{
IApplicationContext context = new XmlApplicationContext(new string[] { "file://context.xml" });

ICaller caller = (ICaller)context.GetObject("Caller");
caller.CallOne();
caller.CallTwo();
}
}

public interface ICaller
{
void CallOne();
void CallTwo();
}

public interface IOne
{
void Execute();
}

public interface ITwo
{
void Execute();
}

public class Target : IOne, ITwo
{
#region IOne Members

void IOne.Execute()
{
System.Console.WriteLine("IOne.Execute");
}

#endregion

#region ITwo Members

void ITwo.Execute()
{
System.Console.WriteLine("ITwo.Execute");
}

#endregion
}


public class Caller : ICaller
{
private IOne m_one;
private ITwo m_two;

public IOne One
{
set
{
m_one = value;
}
}

public ITwo Two
{
set
{
m_two = value;
}
}

#region ICaller Members

public void CallOne()
{
m_one.Execute();
}

public void CallTwo()
{
m_two.Execute();
}

#endregion
}

public class Interceptor : IMethodInterceptor
{
#region IMethodInterceptor Members

public object Invoke(IMethodInvocation invocation)
{
return invocation.Proceed();
}

#endregion
}
}


This is the XML file:


<objects xmlns="http://www.springframework.net">
<description>Root Powerscribe Dictation Client Objects.</description>

<!--====================================== Logging support ===============================================-->

<object id="Caller" type="ProxyTest.Caller">
<property name="One" ref="Target"/>
<property name="Two" ref="Target"/>
</object>


<object id="Target" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
<property name="isSingleton" value="false"/>
<property name="TargetName" value="TargetProxy" />
<property name="InterceptorNames">
<list>
<value>Interceptor</value>
</list>
</property>
</object>

<object id="TargetProxy" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
<property name="isSingleton" value="false"/>
<property name="TargetName" value="RealTarget" />
<property name="InterceptorNames">
<list>
<value>Interceptor</value>
</list>
</property>
</object>

<object id="RealTarget" type="ProxyTest.Target"/>
<object id="Interceptor" type="ProxyTest.Interceptor"/>

</objects>


Could you take a look ?

Bruno Baia
07-26-2007, 09:03 PM
Hi,

thanks for your code, I could reproduce it.
The problems happens when you "proxy a proxy".

For now you can set ProxyFactoryObject.ProxyTargetType property to true to make it work :

<property name="ProxyTargetType" value="True" />

because ProxyTargetType=true uses DecoratorAopProxy that explicitly implements interfaces to proxy contrarily to CompositionAopProxy used when ProxyTargetType=false (default value).


I'm investigating to know why CompositionAopProxy don't explicitly implements interfaces to proxy.


Bruno

a701440
07-26-2007, 10:46 PM
Pardon my ignorance, but what are the trade offs / benefits of using the DecoratorAopProxy vs. the CompositionAopProxy. Any pointers ?

Bruno Baia
07-26-2007, 11:10 PM
ProxyTargetType=true allows you to proxy class with methods that does not belong to an interface by overriding virtual methods.

Reference documentation :
12.5.3. Proxying Interfaces (http://www.springframework.net/doc-latest/reference/html/aop.html#aop-proxying-interfaces)
12.5.4. Proxying Classes (http://www.springframework.net/doc-latest/reference/html/aop.html#d0e7796)

HTH,
Bruno

Bruno Baia
07-28-2007, 01:38 AM
This issue has been resolved and recorded as SPRNET-655 (http://opensource.atlassian.com/projects/spring/browse/SPRNET-655).

Your initial code should work now.


Bruno