Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Generic JSON HTTP Request

0.00/5 (No votes)
6 Mar 2015 1  
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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here