none
Using a third party REST API inside a WCF service

    Question

  • I've got a third party REST API that I'm trying to call using WCF. I've created the contract interface and implemented the data types, and I'm using ClientBase<T> class to invoke the service.  This works fine, until I put the code inside a WCF service so that I can add some more functionality. For some reason, running the client inside a web service changes the GETs going to the third party API into POSTs. This then causes the API to return errors. 

    Does anybody have any suggestions as to what's going wrong?
    Monday, January 18, 2010 3:54 PM

Answers

  • This is caused by the fact that the operation context on the service method (which contains information about the incoming request) overrides the context which should be used by the outgoing request (I hope this will be fixed, or at least better explained in a future release). The workaround for it is to create a new operation context scope when doing the call, so that the call will use the appropriate properties from the [WebGet/WebInvoke] attributes.

    The sample code below shows an example of a ClientBase<T>-based API used to invoke a REST service, within a "normal" service. The workarounds are the "using new OperationContextScope" blocks in the ClientBase subclass.

        public class Post_03a2b109_c400_49d4_891e_03871ae0d083
        {
            static readonly string RestServiceBaseAddress = "http://" + Environment.MachineName + ":8008/Service";
            static readonly string NormalServiceBaseAddress = "http://" + Environment.MachineName + ":8000/Service";
    
            [ServiceContract]
            public interface IRestInterface
            {
                [OperationContract, WebGet]
                int Add(int x, int y);
                [OperationContract, WebGet]
                string Echo(string input);
            }
            [ServiceContract]
            public interface INormalInterface
            {
                [OperationContract]
                int CallAdd(int x, int y);
                [OperationContract]
                string CallEcho(string input);
            }
            public class RestService : IRestInterface
            {
                public int Add(int x, int y)
                {
                    return x + y;
                }
    
                public string Echo(string input)
                {
                    return input;
                }
            }
            public class MyRestClient : ClientBase<IRestInterface>, IRestInterface
            {
                public MyRestClient(string address)
                    : base(new WebHttpBinding(), new EndpointAddress(address))
                {
                    this.Endpoint.Behaviors.Add(new WebHttpBehavior());
                }
    
                public int Add(int x, int y)
                {
                    using (new OperationContextScope(this.InnerChannel))
                    {
                        return base.Channel.Add(x, y);
                    }
                }
    
                public string Echo(string input)
                {
                    using (new OperationContextScope(this.InnerChannel))
                    {
                        return base.Channel.Echo(input);
                    }
                }
            }
            public class NormalService : INormalInterface
            {
                static MyRestClient client = new MyRestClient(RestServiceBaseAddress);
                public int CallAdd(int x, int y)
                {
                    return client.Add(x, y);
                }
    
                public string CallEcho(string input)
                {
                    return client.Echo(input);
                }
            }
            public static void Test()
            {
                ServiceHost restHost = new ServiceHost(typeof(RestService), new Uri(RestServiceBaseAddress));
                restHost.AddServiceEndpoint(typeof(IRestInterface), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
                restHost.Open();
    
                ServiceHost normalHost = new ServiceHost(typeof(NormalService), new Uri(NormalServiceBaseAddress));
                normalHost.AddServiceEndpoint(typeof(INormalInterface), new BasicHttpBinding(), "");
                normalHost.Open();
    
                Console.WriteLine("Hosts opened");
    
                ChannelFactory<INormalInterface> factory = new ChannelFactory<INormalInterface>(new BasicHttpBinding(), new EndpointAddress(NormalServiceBaseAddress));
                INormalInterface proxy = factory.CreateChannel();
    
                Console.WriteLine(proxy.CallAdd(123, 456));
                Console.WriteLine(proxy.CallEcho("Hello world"));
            }
        }
    
    Monday, January 18, 2010 10:51 PM

All replies

  • This is caused by the fact that the operation context on the service method (which contains information about the incoming request) overrides the context which should be used by the outgoing request (I hope this will be fixed, or at least better explained in a future release). The workaround for it is to create a new operation context scope when doing the call, so that the call will use the appropriate properties from the [WebGet/WebInvoke] attributes.

    The sample code below shows an example of a ClientBase<T>-based API used to invoke a REST service, within a "normal" service. The workarounds are the "using new OperationContextScope" blocks in the ClientBase subclass.

        public class Post_03a2b109_c400_49d4_891e_03871ae0d083
        {
            static readonly string RestServiceBaseAddress = "http://" + Environment.MachineName + ":8008/Service";
            static readonly string NormalServiceBaseAddress = "http://" + Environment.MachineName + ":8000/Service";
    
            [ServiceContract]
            public interface IRestInterface
            {
                [OperationContract, WebGet]
                int Add(int x, int y);
                [OperationContract, WebGet]
                string Echo(string input);
            }
            [ServiceContract]
            public interface INormalInterface
            {
                [OperationContract]
                int CallAdd(int x, int y);
                [OperationContract]
                string CallEcho(string input);
            }
            public class RestService : IRestInterface
            {
                public int Add(int x, int y)
                {
                    return x + y;
                }
    
                public string Echo(string input)
                {
                    return input;
                }
            }
            public class MyRestClient : ClientBase<IRestInterface>, IRestInterface
            {
                public MyRestClient(string address)
                    : base(new WebHttpBinding(), new EndpointAddress(address))
                {
                    this.Endpoint.Behaviors.Add(new WebHttpBehavior());
                }
    
                public int Add(int x, int y)
                {
                    using (new OperationContextScope(this.InnerChannel))
                    {
                        return base.Channel.Add(x, y);
                    }
                }
    
                public string Echo(string input)
                {
                    using (new OperationContextScope(this.InnerChannel))
                    {
                        return base.Channel.Echo(input);
                    }
                }
            }
            public class NormalService : INormalInterface
            {
                static MyRestClient client = new MyRestClient(RestServiceBaseAddress);
                public int CallAdd(int x, int y)
                {
                    return client.Add(x, y);
                }
    
                public string CallEcho(string input)
                {
                    return client.Echo(input);
                }
            }
            public static void Test()
            {
                ServiceHost restHost = new ServiceHost(typeof(RestService), new Uri(RestServiceBaseAddress));
                restHost.AddServiceEndpoint(typeof(IRestInterface), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
                restHost.Open();
    
                ServiceHost normalHost = new ServiceHost(typeof(NormalService), new Uri(NormalServiceBaseAddress));
                normalHost.AddServiceEndpoint(typeof(INormalInterface), new BasicHttpBinding(), "");
                normalHost.Open();
    
                Console.WriteLine("Hosts opened");
    
                ChannelFactory<INormalInterface> factory = new ChannelFactory<INormalInterface>(new BasicHttpBinding(), new EndpointAddress(NormalServiceBaseAddress));
                INormalInterface proxy = factory.CreateChannel();
    
                Console.WriteLine(proxy.CallAdd(123, 456));
                Console.WriteLine(proxy.CallEcho("Hello world"));
            }
        }
    
    Monday, January 18, 2010 10:51 PM
  • Thanks for that! I've been pulling my hair out for quite a while.
    Tuesday, January 19, 2010 11:03 AM
  • You are my hero... Thank you very much. I just spent a whole day trying to figure this out.
    Thursday, May 12, 2011 9:00 PM