Sunday, December 2, 2012

WCF : A Simple REST Client using HttpClient

[Articles for WCF REST Services]
1) WCF : A simple WCF REST service example (1)
2) WCF : A Simple WCF REST (2) - Remove .svc in REST URL
3) WCF : A Simple WCF REST (3) - Use WCF REST template
4) Client : WCF : A Simple REST Client using HttpClient 

REST client can be written in many ways such as using AJAX, using .NET APIs, etc. This post shows a simple REST client using one of APIs - HttpClient. The HttpClient is a class in REST Starter Kit that creates a REST client.

The sample client below is a console application that utilizes Microsoft.Http.HttpClient. The sample in this post calls a web service that was created from the previouse post (WCF : A Simple REST service example). (Please note that .svc was removed in REST url for brevity by applying a ASP.NET routing as explained in this post, so let's assume that base address is http://localhost/SimpleRest)

(1) Create a new Console project in VS
(2) Add Reference on Microsoft.Http.dll and Microsoft.Http.Extensions.dll which are installed from REST Starter Kit.
(3) Add DataContract class called Customer. Please note that we set empty string for Namespace in DataContract attribute. The namespace should match the one in server-side DataContract.

using System;
using Microsoft.Http; // for WCF REST Starter Kit
using System.Xml.Linq; // for ReadAsXElement
using System.Runtime.Serialization; // for DataContract
using System.Collections.Generic; 
namespace RestKitClient
{
    class Program
    {
        //test example
        static void Main(string[] args)
        {
            GetAllCustomers();
            AddCustomer();
            GetSingleCustomer();
        }

        static void GetSingleCustomer()
        {
            using (HttpClient client = new HttpClient("http://localhost/SimpleRest/"))
            {
                HttpResponseMessage resp = client.Get("Customer/101");
                resp.EnsureStatusIsSuccessful();
                // Read XML
                string result = resp.Content.ReadAsXElement().ToString();
                Console.WriteLine(result);
            }
        }

        static void GetAllCustomers()
        {
            using (HttpClient client = new HttpClient("http://localhost/SimpleRest/"))
            {
                HttpResponseMessage resp = client.Get("Customers");
                resp.EnsureStatusIsSuccessful();
            
                List<Customer> customers = resp.Content.ReadAsDataContract<List<Customer>>();
                foreach (var c in customers)
                {
                    Console.WriteLine(c.ToString());
                }
            }
        }
        
        static void AddCustomer()
        {
            using (HttpClient client = new HttpClient("http://localhost/SimpleRest/"))
            {
                Customer c = new Customer
                {
                    Id = 101,
                    Name = "Lisa2",
                    Address = "New York"
                };
                var body = HttpContentExtensions.CreateDataContract<Customer>(c);

                HttpResponseMessage resp = client.Send(HttpMethod.POST, "Customer", body);                
                resp.EnsureStatusIsSuccessful();

                Console.WriteLine("Successfully posted");
            }
        }

        // Async BeginSend()
        static void GetAllCustomersAsync()
        {
            HttpClient client = new HttpClient("http://localhost/SimpleRest/");
            HttpRequestMessage req = new HttpRequestMessage("GET", "Customers");
            AsyncCallback callback = (asyncResult) => {
                HttpResponseMessage resp = client.EndSend(asyncResult);
                List<Customer> customers = resp.Content.ReadAsDataContract<List<Customer>>();
                foreach (var c in customers)
                {
                    Console.WriteLine(c.ToString());
                }
            };
            client.BeginSend(req, callback, null);  

            Console.WriteLine("Getting data...");
            Console.WriteLine("Do something in main thread...");
            System.Threading.Thread.Sleep(2000);         
        }
    }
    
    [DataContract(Namespace = "")]
    public class Customer
    {
        [DataMember]
        public int Id;
        [DataMember]
        public string Name;
        [DataMember]
        public string Address;

        public override string ToString()
        {
            return Id + "/" + Name + "/" + Address;
        }
    }
}

(4) Basically all requests such as GET, POST, PUT,DELETE can be sent to web service by using Send() method. But each request also can be called by a little simplified wrapper method. For example, for HTTP GET, HttpClient.Get() method is often used.
To get data from REST service, first create a HttpClient object with base address and then use Get method with relative URL and optional parameter(s). The below URL make a REST call to localhost/simplerest/customer/1.

HttpClient client = new HttpClient("http://localhost/SimpleRest/"))
HttpResponseMessage resp = client.Get("Customer/1");

(5) For HTTP POST, let's use HttpClient.Send() method. To post a new data to REST service, first create a HttpClient object with base address, and build a body content, and call POST with relative URL and a request body. For a request body, it can be string, byte array, stream or DataContract object. Below we used Customer DataContract object.

HttpClient client = new HttpClient("http://localhost/SimpleRest/"))
var body = HttpContentExtensions.CreateDataContract<Customer>(custObj);
HttpResponseMessage resp = client.Send(HttpMethod.POST, "Customer", body);    

HTTP DELETE, PUT requests are similar to POST. We can use Send() method with different HttpMethod enum value. We can also use Post(), Put(), Delete() methods in HttpClient class but they all eventually calls a Send() method under the hood.

(6) For asynchronous processing, BeginSend() or SendAsync() methods can be used instead of synchronous Send() method. GetAllCustomersAsync() method in the example above shows an example of BeginSend(). BeginSend() immediately returns without waiting response and run next statements. When the request is done, callback routine is run and EndSend() returns response from the REST call.

No comments:

Post a Comment