Castle.Windsor Intercept WCF operation return type

588 Views Asked by At

Given this operation contract:

<ServiceContract()>
Public Interface IService1

    <OperationContract()>
    Function GetData(ByVal composite As CompositeType) As CompositeType

End Interface

I create a WCF Client using the Castle.Windsor WCFClientFacility like this:

    container.Register(Component.
                       For(Of IService1).
                       ImplementedBy(Of Service1)().
                       AsWcfClient(New DefaultClientModel() With {
                                   .Endpoint = WcfEndpoint.
                                                BoundTo(New BasicHttpBinding()).
                                                At(String.Format("http://localhost:50310/{0}.svc", "Service1"))
                               }))

This all works fine, but now I want to be able to proxy the return type of the GetData operation, CompositeType. Just registering the CompositeType in the container like this:

    container.Register(Component.For(Of CompositeType).Interceptors(GetType(MyInterceptor))

did not do the trick... Is this behaviour possible? The purpose of this would be implementing INPC on the returning object automatically using a proxy/interceptors. The key would be the possibility to intercept the serializer while it activates a new instance of the CompositeType?

1

There are 1 best solutions below

0
On

The reason that this does not work is that the Castle Windsor client proxy is just a wrapper round the WCF client proxy, and as the WCF client proxy creates the objects returned by service methods they aren't tracked by Castle Windsor. You can, however, intercept the methods of the Castle Windsor client proxy so that when it wants to return a CompositeType you get it to return an intercepted proxy object instead.

Note: For this to work, CompositeType must not be NotInheritable and any methods you want to intercept must be Overridable.

container.Register(Component.
                   For(Of IService1).
                   ImplementedBy(Of Service1)().
                   AsWcfClient(New DefaultClientModel() With {
                               .Endpoint = WcfEndpoint.
                                            BoundTo(New BasicHttpBinding()).
                                            At(String.Format("http://localhost:50310/{0}.svc", "Service1"))
                           })
                   .Interceptors(Of ServiceInterceptor)
)

Also register two interceptors, one (ServiceInterceptor) to intercept the Service method calls, and one (CompositeTypeInterceptor) to intercept the methods of the object returned:

container.Register(
            Component.For(Of ServiceInterceptor)(),
            Component.For(Of CompositeTypeInterceptor)()
)

Here is the code of ServiceInterceptor. It intercepts all methods and, for any which return CompositeType, returns a proxy for CompositeType instead which has all methods intercepted by CompositeTypeInterceptor:

Imports Castle.DynamicProxy
Imports System



Public Class ServiceInterceptor

    Implements IInterceptor

    Private _proxyGenerator As ProxyGenerator
    Private _compositeTypeInterceptor As CompositeTypeInterceptor

    Public Sub New(compositeTypeInterceptor As CompositeTypeInterceptor)

        _proxyGenerator = New ProxyGenerator()
        _compositeTypeInterceptor = compositeTypeInterceptor

    End Sub

    Public Sub Intercept(invocation As IInvocation) Implements IInterceptor.Intercept
        invocation.Proceed()
        If TypeOf invocation.ReturnValue Is CompositeType Then

            invocation.ReturnValue = _proxyGenerator.CreateClassProxyWithTarget(Of CompositeType)(CType(invocation.ReturnValue, CompositeType), New IInterceptor() {_compositeTypeInterceptor})

        End If
    End Sub

End Class

And here is the code of CompositeTypeInterceptor. All it does is print a debug message but you could alter it to do what you want.

Imports Castle.DynamicProxy
Imports System
Imports System.Diagnostics



Public Class CompositeTypeInterceptor
    Implements IInterceptor
    Public Sub Intercept(invocation As IInvocation) Implements IInterceptor.Intercept
        Debug.Print("Intercepted " + invocation.Method.Name)
        invocation.Proceed()
    End Sub
End Class