Search code examples
c#wcfserviceproxychannelfactory

How to fire an event (client side) when I call a WCF service


I'd like to fire an event every time I call a WCF service.

I've tried the following:

var factory = new ChannelFactory<TService>(binding, endPointAdress);

factory.Credentials.UserName.UserName = username;
factory.Credentials.UserName.Password = password;

var proxy = factory.CreateChannel();

((IContextChannel)this.Proxy).Opened += new EventHandler(FactoryOpeningEventHandler);
this.Factory.Opened += new EventHandler(FactoryOpeningEventHandler);

The problem with the above is that the event is only called when the proxy is opened, but I want to fire the event when a call is made trough this proxy, not only when it opens. I know there is no event for the IContextChannel that can do what I want, so I would like to have a workaround.


Solution

  • You start by creating an inspector class that implement both IDispatchMessageInspector (when sending) and IClientMessageInspector (when receiving) interfaces.

    public class SendReceiveInspector : IDispatchMessageInspector, IClientMessageInspector
    {
    
        public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
        {
            // TODO: Fire your event here if needed
            return null;
        }
        public void BeforeSendReply(ref Message reply, object correlationState)
        {
            // TODO: Fire your event here if needed
        }
    
        public void AfterReceiveReply(ref Message reply, object correlationState)
        {
            // TODO: Fire your event here if needed
        }
    
        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            // TODO: Fire your event here if needed
            return null;
        }
    }
    

    After you have your inspector class, you have to register it through a behaviour.

    public class SendReceiveBehavior : IEndpointBehavior, IServiceBehavior
    {
        void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            clientRuntime.MessageInspectors.Add(new SendReceiveInspector());
        }
    
        void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
            endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new SendReceiveInspector());
        }
    
        void IEndpointBehavior.AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
            // Leave empty
        }
    
        void IEndpointBehavior.Validate(ServiceEndpoint endpoint)
        {
            // Leave empty
        }
    
        void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription desc, ServiceHostBase host)
        {
            foreach (ChannelDispatcher cDispatcher in host.ChannelDispatchers)
            {
                foreach (EndpointDispatcher eDispatcher in cDispatcher.Endpoints)
                {
                    eDispatcher.DispatchRuntime.MessageInspectors.Add(new SendReceiveInspector());
                }
            }
        }
    
        void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
            // Leave empty
        }
    
        void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            // Leave empty
        }
    }
    

    Finally, you have to register that behaviour to your service description:

    host.Description.Behaviors.Add(new SendReceiveBehavior ());
    foreach (ServiceEndpoint se in host.Description.Endpoints)
        se.Behaviors.Add(new SendReceiveBehavior ());
    

    You can learn more about extending WCF at http://msdn.microsoft.com/en-us/magazine/cc163302.aspx