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 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 customerList = null; public Service1() { customerList = new List(); // 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 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. http://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 http://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("http://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("http://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("http://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("http://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="http://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 (http://localhost:8080/myrestservice/help)
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("http://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.