Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the invoked operation name within a IClientMessageInspector?

I implemented an IClientMessageInspector to "intercept" outgoing web service call in my application. Is it possible to find out which operation is being called from inside the BeforeSendRequest and AfterReceiveReply?

There is a similar question here, How do i get the invoked operation name within a WCF Message Inspector, which is for the server side (the side receiving the request). I tried to do something similar, e.g.

    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        var v = OperationContext.Current.OutgoingMessageProperties["HttpOperationName"];
        return null;
    }

    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
        var v = OperationContext.Current.OutgoingMessageProperties["HttpOperationName"];
    }

but during outgoing request it seems that OperationContext.Current is null, so I cannot use this. Any idea how to get it? Any idea how to do it cleanly (as opposed, to say, parse the SOAP xml)?

like image 240
Louis Rhys Avatar asked Apr 16 '13 06:04

Louis Rhys


2 Answers

From the comments you asked how doing this could be done with IParameterInspector. The operation name is part of the Before/AfterCall methods.

Just to add to my comments on which inspector to use. From Carlos Figueira's blogs:

The message inspectors, described in the previous post of this series, allows you complete control over the message going through the WCF stack. They’re very powerful, but you have to know how to deal with the Message object, which is not the most desirable way of programming. If the service model in WCF hides all the messaging framework by allowing us to define our services in terms of strongly-typed operations (i.e., using nice primitive and user defined types), there should be a way of intercepting requests / responses after all the processing to extract those parameters from incoming messages (or before they’re packaged in outgoing messages) is done. The IParameterInspector is exactly that – before and after each call, the inspector gets a chance to inspect the operation inputs, outputs and return value, in the same types as defined by the operation contract, no conversion needed (the only thing needed is a cast, since the parameters are passed as objects).

This is a complete command line program that demonstrates:

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;

namespace WCFClientInspector
{
    public class OperationLogger : IParameterInspector
    {
        public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
        {
            Console.WriteLine("Completed operation:" + operationName);
        }

        public object BeforeCall(string operationName, object[] inputs)
        {
            Console.WriteLine("Calling operation:" + operationName);
            return null;
        }
    }

    public class OperationLoggerEndpointBehavior : IEndpointBehavior
    {
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            foreach (ClientOperation operation in clientRuntime.ClientOperations)
            {
                operation.ClientParameterInspectors.Add(new OperationLogger());
            }
        }

        public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
        {
        }

        public void Validate(ServiceEndpoint endpoint)
        {
        }
    }


    [ServiceContract]
    public interface ISimple
    {
        [OperationContract]
        void DoSomthing(string s);
    }

    public class SimpleService : ISimple
    {
        public void DoSomthing(string s)
        {
            Console.WriteLine("Called:" + s);
        }
    }

    public static class AttributesAndContext
    {
        static void Main(string[] args)
        {
            ServiceHost simpleHost = new ServiceHost(typeof(SimpleService), new Uri("http://localhost/Simple"));
            simpleHost.Open();

            ChannelFactory<ISimple> factory = new ChannelFactory<ISimple>(simpleHost.Description.Endpoints[0]);
            factory.Endpoint.EndpointBehaviors.Add(new OperationLoggerEndpointBehavior());
            ISimple proxy = factory.CreateChannel();

            proxy.DoSomthing("hi");

            Console.WriteLine("Press ENTER to close the host.");
            Console.ReadLine();

            ((ICommunicationObject)proxy).Shutdown();

            simpleHost.Shutdown();
        }
    }

    public static class Extensions
    {
        static public void Shutdown(this ICommunicationObject obj)
        {
            try
            {
                obj.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Shutdown exception: {0}", ex.Message);
                obj.Abort();
            }
        }
    }
}

It should give the output:

  Calling operation:DoSomthing 
  Called:hi 
  Completed operation:DoSomthing
  Press ENTER to close the host.
like image 112
ErnieL Avatar answered Sep 21 '22 16:09

ErnieL


What about reply.Headers.Action and request.Headers.Action. Of course the rest is same tricky as in question linked. So the full code will be:

var action = reply.Headers.Action.Substring(reply.Headers.Action.LastIndexOf("/", StringComparison.OrdinalIgnoreCase) + 1);

or

var action = request.Headers.Action.Substring(request.Headers.Action.LastIndexOf("/", StringComparison.OrdinalIgnoreCase) + 1);
like image 22
Piotr Stapp Avatar answered Sep 24 '22 16:09

Piotr Stapp