WCF: Consume WCF REST service by HttpClient

In a recent case, one of my customers requested how to consume the WCF REST Service by taking the help of System.Net.Http.HttpClient modules (introduced in .NET 4.5). I hope the following details would help in depth.

 

Create a new WCF service application project named "RestService"

  • WCF REST service contract appears as the following.
       namespace RestService
       {
           [ServiceContract]
           public interface IService1
          {
       
                [OperationContract]
             [WebInvoke(Method ="GET", ResponseFormat = WebMessageFormat.Json,
                   UriTemplate = "get/{value}")]
               string GetData(string value);
       
                [OperationContract]
             [WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json,
                 UriTemplate = "get/add")]
               string AddData(int value);
      
                [OperationContract]
             [WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json,
                  UriTemplate = "GetCustomer/{customerId}")]
              Customer GetCustomer(string customerId);
        
                [OperationContract]
             [WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json,
                 UriTemplate = "UpdateCustomer")]
                List<Customer> UpdateCustomer(Customer customer);
         }
       
            [DataContract]
          public class Customer
           {
                   [DataMember]
                    public string Id { get; set; }
                  [DataMember]
                    public string FirstName { get; set; }
                   [DataMember]
                    public string LastName { get; set; }
                    [DataMember]
                    public string SSN { get; set; }
         }
                 }

 

  • The WCF REST service implementation appears as the following.
       namespace RestService
       {
           public class Service1 : IService1
           {
               public static List<Customer> customerList = null;
     
                public Service1()
               {
                   customerList = new List<Customer>();
      
                    // Currently, it is statically loaded with dummy values.
                    // However, it can be extended to populate from a data source (e.g. SQL).
                   customerList.Add(new Customer
                   {
                       Id = "1111",
                        FirstName = "John",
                     LastName = "Doe",
                       SSN = "451234590"
                   });
                 customerList.Add(new Customer
                   {
                       Id = "1112",
                        FirstName = "Jason",
                        LastName = "Rudd",
                      SSN = "451234592"
                   });
                 customerList.Add(new Customer
                   {
                       Id = "1113",
                        FirstName = "Daniel",
                       LastName = "Cheng",
                     SSN = "451234596"
                   });
             }
               
                public string GetData(string value)
             {
                   return string.Format("You entered: {0}", value);
                }
       
                public string AddData(int value)
                {
                   return string.Format("You entered: {0}", value);
                }
       
                public Customer GetCustomer(string customerId)
              {
                   //TODO: query your repo and pull customer details
                   return customerList.Find(t => t.Id == customerId);
               }
               
                public List<Customer> UpdateCustomer(Customer customer)
               {
                   //TODO: update customer information in your repo
                    var targetCustomer = customerList.Where(t => t.Id == customer.Id).FirstOrDefault();
      
                    if (targetCustomer != null)
                 {
                       // no need to update cutomerId
                      targetCustomer.FirstName = customer.FirstName;
                      targetCustomer.LastName = customer.LastName;
                        targetCustomer.SSN = customer.SSN;
                  }
       
                    return customerList;
                }
           }
                 }

 

  • Web.config should be updated like the following for WCF REST service hosting on IIS.
       <system.serviceModel>
         <behaviors>
             <serviceBehaviors>
              <behavior>
                  <serviceMetadata httpGetEnabled="true"/>
                  <serviceDebug includeExceptionDetailInFaults="true"/>
               </behavior>             
                  <endpointBehaviors>
             <behavior name="ep">
                <webHttp helpEnabled="true"/>
           </behavior>
         </endpointBehaviors>
          </behaviors>
          <services>
              <service name="RestService.Service1">
               <endpoint address=""
                       binding="webHttpBinding" bindingConfiguration="webh" behaviorConfiguration="ep" contract="RestService.IService1"/>
           </service>
          </services>
           <bindings>
            <!-- The following customBinding can be used if intention is to convert "webHttpBinding" to "customBinding" for some reason. -->
            <customBinding>
             <binding name="webHttpDeviceBinding">
               <webMessageEncoding>
                    <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
                    maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
               </webMessageEncoding>
                 <httpTransport manualAddressing="true" maxBufferPoolSize="2147483647"
                  maxReceivedMessageSize="2147483647" authenticationScheme="None"
                 maxBufferSize="2147483647" maxPendingAccepts="15" transferMode="Buffered" />
             </binding>
              <webHttpBinding>
                <binding name="webh">
               <security mode="None" />
                </binding>
                <binding name="webHttpDeviceBinding" closeTimeout="00:10:00"
               openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00"
                 maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
               transferMode="Buffered">
                 <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
                    maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
                 <security mode="None" />
                </binding>
              </webHttpBinding>
           </bindings>
           <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
             </system.serviceModel>

 

Host the WCF REST service application on IIS

  • Create an application pool named "RestServicePool"
  • Right click on VS project "RestService" -> Go to "Web" section -> set server to "Local IIS"/ prepare your path and "Create Virtual Directory"
  • Application would be deployed on IIS
  • Select the application on IIS manager -> Go to "Advanced Settings" -> Set the application pool to your pool "RestServicePool"

 

Check if you are able to read "metadata" of the WCF REST service

  • Browse the help URL (e.g. <pupanda-win10.fareast.corp.microsoft.com/RestService/Service1.svc/help>)
  • Screenshot for reference

Consume the REST service by HttpClient

  • Create a console application named "RestClient"
  • "Add Service Reference" to your service URL <pupanda-win10.fareast.corp.microsoft.com/RestService/Service1.svc> [reason to go for the plan of downloading proxy classes w.r.t. service classes, is to  ensure that custom classes can smoothly be "de-serialized" or "serialized"]
  • Go to your "Program.cs", update the definition with the following code snippet

 

         private static async Task PostResult()
              {
                   HttpResponseMessage response = null;
        
                    using (var client = new HttpClient())
                   {
                       var uri = new Uri("pupanda-win10.fareast.corp.microsoft.com/RestService/Service1.svc/get/add");
                      var jsonRequest = JsonConvert.SerializeObject("123");
                       var stringContent = new StringContent(jsonRequest, Encoding.UTF8, "application/json");
                      response = await client.PostAsync(uri, stringContent);
                  }
       
                    Console.WriteLine(await response.Content.ReadAsStringAsync());
              }
       
                private static async Task GetResult()
               {
                   string response = null;
     
                    using (var client = new HttpClient())
                   {
                       var uri = new Uri("pupanda-win10.fareast.corp.microsoft.com/RestService/Service1.svc/get/123");
                      response = await client.GetStringAsync(uri);
                    }
       
                    Console.WriteLine(response);
                }
       
                private static async Task GetCustomerResult()
               {
                   string response = null;
     
                    using (var client = new HttpClient())
                   {
                       var uri = new Uri("pupanda-win10.fareast.corp.microsoft.com/RestService/Service1.svc/GetCustomer/1113");
                     response = await client.GetStringAsync(uri);
                    }
       
                    Console.WriteLine(response);
                }
       
                private static async Task PostCustomerResult()
              {
                   HttpResponseMessage response = null;
        
                    using (var client = new HttpClient())
                   {
                       var uri = new Uri("pupanda-win10.fareast.corp.microsoft.com/RestService/Service1.svc/UpdateCustomer");
                       Customer toUpdateCustomer = new Customer {
                          Id = "1113",
                            FirstName = "Daniel",
                           LastName = "Gates",
                         SSN = "4512xx596"
                       };
                      var jsonRequest = JsonConvert.SerializeObject(toUpdateCustomer);
                        var stringContent = new StringContent(jsonRequest, Encoding.UTF8, "application/json");
                      response = await client.PostAsync(uri, stringContent);
                  }
       
                    Console.WriteLine(await response.Content.ReadAsStringAsync());
              }
       
                static void Main(string[] args)
             {
                   Console.WriteLine("Press 1 for GET String/ Press 2 for POST String/ Press 3 for GET Customer/ Press 4 for POST Customer");
                  var input = Console.ReadLine();
                 switch (input)
                  {
                       case "1":
                           Console.Write("Results from GET operation: ");
                          Task.Run(() => GetResult());
                         break;
                      case "2":
                           Console.Write("Results from POST operation: ");
                         Task.Run(() => PostResult());
                            break;
                      case "3":
                           Console.Write("Results from GET Customer operation: ");
                         Task.Run(() => GetCustomerResult());
                         break;
                      case "4":
                           Console.Write("Results from POST Customer operation: ");
                            Task.Run(() => PostCustomerResult());
                            break;
                      default:
                            Console.WriteLine("wrong option");
                          break;
                  }
       
                    Console.ReadLine();
        }

 

Self-host the WCF REST Service

  • Create a console application named "RestServiceSelfHost"
  • Add reference to the "RestService" project
  • Update the "App.config" with following content
             
      <system.serviceModel>    
         <services>
              <service name="RestService.Service1">
               <host>
                  <baseAddresses>
                 <add baseAddress="localhost:8080/myrestservice"/>
                </baseAddresses>
                </host>
               <endpoint address=""
                       binding="webHttpBinding"
                        behaviorConfiguration="epB"
                         contract="RestService.IService1"/>
           </service>
          </services>
           <behaviors>
             <endpointBehaviors>
             <behavior name="epB">
               <webHttp helpEnabled="true"/>
               </behavior>
             </endpointBehaviors>
            </behaviors>
      </system.serviceModel>            
  • Update the Program.cs with following content
       static void Main(string[] args)
             {
                   using (ServiceHost host = new ServiceHost(typeof(Service1)))
                    {
                       host.Open();
        
                        Console.WriteLine("The service is ready at {0}", host.Description.Endpoints[0].Address);
                        Console.WriteLine("Press  to stop the service.");
                       Console.ReadLine();
     
                        // Close the ServiceHost.
                       //host.Close();
                 }
                       }

 

  • Run the application
  • You should be able to browse to help page ()

 

Consume the self-hosted WCF REST service by HttpClient

  • Create a console application named "RestServiceSelfHostClient"
  • Update your "Program.cs" with the following section of code
        static void Main(string[] args)
                {
                   Console.Write("Results from GET operation: ");
                  Task.Run(() => GetResult());
     
                    Console.ReadLine();
             }
       
                private static async Task GetResult()
               {
                   string response = null;
     
                    using (var client = new HttpClient())
                   {
                       var uri = new Uri("localhost:8080/myrestservice/get/123");
                       response = await client.GetStringAsync(uri);
                    }
       
                    Console.WriteLine(response);
                }

 

Note

I have uploaded the whole sample application for your reference in OneDrive. It is a one solution having all the above details.