none
Urgent help needed: Request Interceptor in RESTful Service

    Question

  • I have a RESTful service and now i wanted to add instrumentation around the service methods. I.e, I need to log the start time and end time of the service method execution. When i look on the interceptor class, we have only the ProcessRequest() method which is executed before the actual method is invoked. I can record the startTime in the ProcessRequest() method. But i'm not sure in which method i can record the end time.

    i noticed that there are other two methods for asynchronous calls. Is it possible to achieve the above requirements using these 2 methods.
    Kindly help me to understand if the requirement is achievable using the request interceptor.

    Thanks in advance.

    Regards,
    Ranjith
    Monday, March 01, 2010 6:47 PM

Answers

  • Yes, you can use an IDispatchMessageInspector (or some other extensibility point, such as IParameterInspector) to accomplish this. The code below hooks to the REST endpoint, and prints out how much time it took for each operation.

        public class Post_65778aea_f872_45a8_85c9_d2bbc2838baf
        {
            [ServiceContract]
            public interface ITest
            {
                [OperationContract]
                string Echo(string text);
                [OperationContract]
                [WebInvoke(BodyStyle = WebMessageBodyStyle.WrappedRequest)]
                string LongEcho(string text, int delay);
                [OperationContract]
                [WebGet]
                int Add(int x, int y);
            }
            public class Service : ITest
            {
                public string Echo(string text)
                {
                    return text;
                }
    
                public string LongEcho(string text, int delay)
                {
                    Thread.Sleep(delay);
                    return text;
                }
    
                public int Add(int x, int y)
                {
                    Thread.Sleep(500);
                    return x + y;
                }
            }
            public class MyInspector : IEndpointBehavior, IDispatchMessageInspector
            {
                public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
                {
                }
    
                public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
                {
                }
    
                public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
                {
                    endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
                }
    
                public void Validate(ServiceEndpoint endpoint)
                {
                }
    
                Dictionary<Guid, KeyValuePair<string, DateTime>> callTimes = new Dictionary<Guid,KeyValuePair<string,DateTime>>();
                static object syncRoot = new object();
                Guid StartCallingMethod(string action)
                {
                    lock (syncRoot)
                    {
                        Guid correlation = Guid.NewGuid();
                        callTimes.Add(correlation, new KeyValuePair<string, DateTime>(action, DateTime.Now));
                        return correlation;
                    }
                }
                void EndCallingMethod(Guid correlation)
                {
                    DateTime now = DateTime.Now;
                    KeyValuePair<string, DateTime> beginData;
                    lock (syncRoot)
                    {
                        beginData = callTimes[correlation];
                        callTimes.Remove(correlation);
                    }
                    Console.WriteLine("Request to {0} took {1}", beginData.Key, now.Subtract(beginData.Value));
                }
                public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
                {
                    return StartCallingMethod(WebOperationContext.Current.IncomingRequest.UriTemplateMatch.RequestUri.ToString());
                }
    
                public void BeforeSendReply(ref Message reply, object correlationState)
                {
                    EndCallingMethod((Guid)correlationState);
                }
            }
            public static void Test()
            {
                string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
                ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
                ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(ITest), new WebHttpBinding(), "");
                endpoint.Behaviors.Add(new WebHttpBehavior());
                endpoint.Behaviors.Add(new MyInspector());
                host.Open();
                Console.WriteLine("Host opened");
    
                ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new WebHttpBinding(), new EndpointAddress(baseAddress));
                factory.Endpoint.Behaviors.Add(new WebHttpBehavior());
                ITest proxy = factory.CreateChannel();
                Console.WriteLine(proxy.Echo("Hello"));
                Console.WriteLine(proxy.LongEcho("World", 1234));
                Console.WriteLine(proxy.Add(3, 4));
    
                ((IClientChannel)proxy).Close();
                factory.Close();
    
                Console.Write("Press ENTER to close the host");
                Console.ReadLine();
                host.Close();
            }
        }
    
    • Proposed as answer by Carlos Figueira Friday, March 05, 2010 6:21 PM
    • Marked as answer by Mog Liang Tuesday, March 09, 2010 2:45 AM
    Monday, March 01, 2010 9:25 PM