Reputation: 18289
I've got a simple decorator class like the following. Notice how my public methods all create a new instance of the to-be-decorated class, then forward the call to that instance.
The problem with this class is that whenever IMyService
gets updated, I have to update this proxy class too.
public class MyProxyService : IMyService
{
readonly IMyServiceFactory _realServiceFactory;
public MyProxyService(IMyServiceFactory realServiceFactory)
{
_realServiceFactory = realServiceFactory;
}
private IMyService CreateRealService()
{
return _realServiceFactory.CreateRealService();
}
public int A()
{
return CreateRealService().A();
}
public int B(int b1)
{
return CreateRealService().B(int b1);
}
public int C(int c1, int c2)
{
return CreateRealService().C(c1,c2);
}
public int D(int d1, int d2, int d3)
{
return CreateRealService().D(d1,d2,d3);
}
public void E()
{
CreateRealService().E();
}
}
I've tried creating a dynamic version using Castle.DynamicProxy
, without any luck so far.
Anyone know a good, simple way to dynamically create a decorator like this?
Upvotes: 0
Views: 1366
Reputation: 18289
I was able to get this to work using DynamicProxy.ProxyGenerator
's CreateInterfaceProxyWithTargetInterface(..) .
I first created a dynamic proxy factory. This returns a proxy object, for which each method will be intercepted by the provided IInterceptor
:
public class MyDynamicallyDecoratedServiceClientFactory
{
readonly ProxyGenerator _proxyGenerator;
readonly IInterceptor _interceptor;
public MyServiceClientFactory(IInterceptor interceptor)
{
_interceptor = interceptor;
_proxyGenerator = new ProxyGenerator();
}
public IMyService Create()
{
IMyService proxy = _proxyGenerator.CreateInterfaceProxyWithTargetInterface<IMyService>(null, _interceptor);
return proxy;
}
}
I then implemented the interceptor. Upon each method call, this interceptor will be called, which will create a new IMyService
from the provided IMyServiceFactory
, and delegate the method call to that new instance.
public class MyServiceClientInterceptor : IInterceptor
{
readonly IMyServiceFactory _svcFactory;
public MyServiceClientInterceptor(IMyServiceFactory svcFactory)
{
_svcFactory = svcFactory;
}
public void Intercept(IInvocation invocation)
{
IMyService realService = _svcFactory.Create();
IChangeProxyTarget changeProxyTarget = invocation as IChangeProxyTarget;
changeProxyTarget.ChangeInvocationTarget(realService);
invocation.Proceed();
}
}
Finally, to make use of all this:
// Create a service factory (the to-be-decorated class)
IMyServiceFactory myRealServiceFactory = /* ... */;
// Create a factory that will create decorated services
MyServiceClientInterceptor interceptor =
new MyServiceClientInterceptor(myRealServiceFactory);
MyDynamicallyDecoratedServiceClientFactory svcFactory =
new MyDynamicallyDecoratedServiceClientFactory(interceptor);
// Create a service client
IMyService svc = svcFactory.Create();
// Use it!
svcProxy.A();
Upvotes: 4