REST web service client in C#

Here is an example of how to do REST web requests in C#. The example shown is POST but for GET just remove the request body stuff and change the request.Method:

updated with checks for Basic Auth and GET requests

// Create a request and set the headers
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "POST"
request.ContentType = contentType
request.UserAgent = userAgent
request.Timeout = timeout

if (useBasicAuth == true)
{
    // Create a token for basic authentication and add a header for it
    String authorization = System.Convert.ToBase64String(Encoding.UTF8.GetBytes(username + ":" + password));
    request.Headers.Add("Authorization", "Basic " + authorization)
}

if (request.Method == "POST"  && requestBody != null)
{
    // Convert the request contents to a byte array and include it
    byte[] requestBodyBytes = System.Text.Encoding.UTF8.GetBytes(requestBody);
    Stream requestStream = request.GetRequestStream();
    requestStream.Write(requestBodyBytes, 0, requestBodyBytes.Length);
    requestStream.Close();
}

// Initialize the response
HttpWebResponse response = null;
String responseText = null;

// Now try to send the request
try {
    response = request.GetResponse() as HttpWebResponse;

    // expect the unexpected
    // WebException may be thrown already for some of this already 
    // like timeout or 404
    if (request.HaveResponse == true && response == null) {
        String msg = "response was not returned or is null";
        throw new WebException(msg);
    }
    if (response.StatusCode != HttpStatusCode.OK) {
        String msg = "response with status: " + response.StatusCode + " " + response.StatusDescription;
        throw new WebException(msg);
    }

    // check response headers for the content type
    contentType = response.GetResponseHeader("Content-Type");

    // get the response content
    StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
    responseText = reader.ReadToEnd();
    reader.Close();

// handle failures
} catch (WebException e) {
    if (e.Response != null) {
        response = (HttpWebResponse) e.Response;
        log.Error(response.StatusCode + " " + response.StatusDescription);
    } else {
        log.Error(e.Message);
    }

// and clean up after ourselves
} finally {
    if (response != null) {
        response.Close();
    }
}

// display the response
if (responseText != null) {
   System.Console.Write(responseText);
}

As you can see, there’s a lot of drudgework here — and this is an abbreviated example. Ideally, I’d like to wrap it all up in a class with a pretty bow so I can do something like this:

RestClient client = new RestClient();
System.Console.Write(client.get(url));

Of course a more complex example might look more like this:

var settings = new Dictionary<String, String> {
   {"key1", "value1"},
   {"key2", "value2"}
};

RestClient client = new RestClient(settings);
client.Url = "http://rest.example.com/1/resource/method?param=value"
client.BasicAuth("username", "password");
client.Headers.Add("header", "value");

client.post("content")

System.Console.WriteLine(client.Response.Body);

foreach (KeyValuePair<String, String> header in client.Response.Headers) {
    System.Console.WriteLine(header.Key ": " + header.Value);
}

if (client.Response.Error) {
    System.Console.WriteLine(client.Response.StatusCode)
    System.Console.WriteLine(client.Response.Error.Message)
}

Then I could simply extend RestClient to handle things like urls, parameters, and custom headers for each webservice client class.

Currently, I’m sorry to admit I have a jumble of cut & paste code that intermingles JSON serialization with HttpWebRequest handling — but at least I’ve abstracted out URLs & stream handling into a base class.

For maintainability (by someone else) I’ve avoided extending HttpWebRequest and HttpWebResponse to make them less painful. Also, by not allowing default constructors, I’d have to end up using composition.

I’ve looked at other libraries, like Hammock, but I don’t really see much value added. The level of abstraction it uses for just the 2 lines of basic auth code is staggering.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s