Click here to Skip to main content
16,006,442 members
Articles / Programming Languages / C# 4.0
Tip/Trick

Generic JSON HTTP Request

Rate me:
Please Sign up or sign in to vote.
1.00/5 (1 vote)
6 Mar 2015CPOL1 min read 13.3K   189   4  
A generic type web request serialingn json response

Generic Json HTTP Request

Ok, you are asked to create an application to send some product codes encoded as JSON to a web API and receive an id code in the response. So you create your class which holds the data to send, and a trivial class to receive the response. The data is encoded to JSON using .NET's DataContractJsonSerializer, encoded again to a byte[] array and passed to your new (HttpWebRequest).

All's good, you receive a response, and using the DataContractJsonSerializer.ReadObject method, the response stream is serialized into your trivial class.

You give yourself a pat on the back and have that warm fuzzy feeling inside you. The world is right again.

Now For A Reality Check

Another request comes in; can your app send a different set of data, oh and the response is going to be an address with 5 lines, and latitude and longitude points.

Gulp ... your trivial class isn't going to be able to hold all that data in the response, and you are going to need to re-write the code which handled sending the request and receiving the response.

A Generic Request

First, let's re-write our web request class using Generics, a heavily talked about subject. This means we can pass any class to receive the response without the need to replicate code.

using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Runtime.Serialization.Json;
using System.Security.Cryptography.X509Certificates;

namespace HTTPRequestDemo 
{
    public class HTTPRequest<T> where T : class 
    { 
        // We will need a callback function
        public delegate void CallbackHandler(object sender, T t);
        
        private CallbackHandler callbackHandler;
        
        // The host
        private readonly string host;
 
        // The method to use, i.e POST or GET
        private readonly string method;

        // As the response stream in this instance is always going to be JSON...
        const string type = @"application/json";
        
        // The constructor
        public HTTPRequest(string h, string m, CallbackHandler callback)
        {
            host = h;

            method = m;

            callbackHandler = callback;
        }

        public void Post(byte[] bytes, string uri)
        {
            // For HTTPS requests add this callback.
            ServicePointManager.ServerCertificateValidationCallback += 
		new System.Net.Security.RemoteCertificateValidationCallback(Accept);

            var len = bytes.Length;
            // Create request... 
            var request = (HttpWebRequest)WebRequest.Create(uri);
            request.Proxy = null;
            request.Credentials = CredentialCache.DefaultCredentials;
            request.ContentLength = len;
            request.ContentType = type;
            request.Accept = type;
            request.Method = method;
            request.Host = host;

            var dataStream = request.GetRequestStream();

            dataStream.Write(bytes, 0, len);

            dataStream.Close();

            try
            {
                var t = Read((HttpWebResponse)request.GetResponse());
                
                // Pass the response back already encoded into any class
                callbackHandler(this, t);
            }
            catch (Exception)
            {
                callbackHandler(this, default(T));
            }
        }

        private T Read(HttpWebResponse resp)
        {
            DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(T));

            T e;

            using (MemoryStream memoryStream = new MemoryStream())
            {
                // Read in the response
                e = (T)jsonSerializer.ReadObject(resp.GetResponseStream());

                memoryStream.Close();
            }

            resp.Close();

            return e;
        }
        
        private bool Accept(object sender, X509Certificate cert, X509Chain chn, SslPolicyErrors ssl)
        {
            return true;
        }        
    }
}

And to consume this class in your application. Firstly, you'll need a label to hold some data from the response, you choose, and a delegate to stop any cross thread contamination.

delegate void UpdateCrossThreadCallback(object sender, object text);

And a method to receive the response.

private void ReceiveResponse(object sender, object e)
{
    if (label1.InvokeRequired)
    {
        UpdateCrossThreadCallback d = new UpdateCrossThreadCallback(ReceiveResponse);

        this.Invoke(d, new object[] { sender, e });
    }
    else
    {
        var result = (MyResponseClass)e;

        label1.Text = result.id;
    }
}

Now, maybe on a click event of a button.

var ASCIIEncoder = new ASCIIEncoding();

//Encode your JSON string into a byte array

byte[] bits = ASCIIEncoder.GetBytes(jsonString);

// Create the request with a callback function to receive the response
var request = new HTTPRequest<MyResponseClass>("web.api.co.uk", "POST", ReceiveResponse);

// Wrap in a task for a responsive ui.  the response will be received in the method ReceiveResponse.
Task.Factory.StartNew(() => request.Post(bits, uri));

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --