Search code examples
c#jsonhttpwebrequest

How do I create multi level json and pass it as a web request?


I am attempting to connect to an api and pass it a json request. I wasn't sure how to format the json data so I found a post suggesting json2csharp.com.

So, I used http://json2csharp.com/ to create the classes I needed for the json request data:

curl -v -X POST \
  -H "Authorization: APIKEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "sale",
    "amount": 1112,
    "tax_amount": 100,
    "shipping_amount": 100,
    "currency": "USD",
    "description": "test transaction",
    "order_id": "someOrderID",
    "po_number": "somePONumber",
    "ip_address": "4.2.2.2",
    "email_receipt": false,
    "email_address": "user@home.com",
    "create_vault_record": true,
    "payment_method": {
        "card": {
          "entry_type": "keyed",
          "number": "4012000098765439",
          "expiration_date": "12/20",
          "cvc": "999",
          "cardholder_authentication": {
            "condition": "...",
            "eci": "...",
            "cavv": "...",
            "xid": "...",
          }
        }
        ... or ...
        "customer": {
          "id": "b798ls2q9qq646ksu070",
          "payment_method_type": "card",
          "payment_method_id": "b798ls2q9qq646ksu080",
          "billing_address_id": "b798ls2q9qq646ksu07g",
          "shipping_address_id": "b798ls2q9qq646ksu07g"
        }
        ... or ...
        "terminal": {
          "id": "<terminal id>"
          "expiration_date": "12/20",
          "cvc": "999",
          "print_receipt": "both"
          "signature_required": true
        }
        ... or ...
        "token": "<tokenizer token goes here>",
        ... or ...
        "ach": {
          "routing_number": "490000018",
          "account_number": "999999", 
          "sec_code": "ccd",
          "account_type": "checking",
          "check_number":"1223",
          "accountholder_authentication": {
            "dl_state": "IL",
            "dl_number": "r500123123"
          }
          ... or ...
        "apm": {
          "type": "alipay",
          "merchant_redirect_url": "http://merchantwebsite.com/",
          "locale": "en-US",
          "mobile_view": false
        }
      }
    },
    "billing_address" : {
        "first_name": "John",
        "last_name": "Smith",
        "company": "Test Company",
        "address_line_1": "123 Some St",
        "city": "Wheaton",
        "state": "IL",
        "postal_code": "60187",
        "country": "US",
        "phone": "5555555555",
        "fax": "5555555555",
        "email": "help@website.com"
    },
    "shipping_address" : {
        "first_name": "John",
        "last_name": "Smith",
        "company": "Test Company",
        "address_line_1": "123 Some St",
        "city": "Wheaton",
        "state": "IL",
        "postal_code": "60187",
        "country": "US",
        "phone": "5555555555",
        "fax": "5555555555",
        "email": "help@website.com"
    }
}'   \
"URL_GOES_HERE/transaction"

Here are the results from the website:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Test
{
  public class ApiRequest
  {
    public class ProcessorSpecific
    {
    }

    public class Card
    {
      public string id { get; set; }
      public string card_type { get; set; }
      public string first_six { get; set; }
      public string last_four { get; set; }
      public string masked_card { get; set; }
      public string expiration_date { get; set; }
      public string status { get; set; }
      public string auth_code { get; set; }
      public string processor_response_code { get; set; }
      public string processor_response_text { get; set; }
      public string processor_type { get; set; }
      public string processor_id { get; set; }
      public string avs_response_code { get; set; }
      public string cvv_response_code { get; set; }
      public ProcessorSpecific processor_specific { get; set; }
      public DateTime created_at { get; set; }
      public DateTime updated_at { get; set; }
    }

    public class Response
    {
      public Card card { get; set; }
    }

    public class BillingAddress
    {
      public string first_name { get; set; }
      public string last_name { get; set; }
      public string company { get; set; }
      public string address_line_1 { get; set; }
      public string address_line_2 { get; set; }
      public string city { get; set; }
      public string state { get; set; }
      public string postal_code { get; set; }
      public string country { get; set; }
      public string phone { get; set; }
      public string fax { get; set; }
      public string email { get; set; }
    }

    public class ShippingAddress
    {
      public string first_name { get; set; }
      public string last_name { get; set; }
      public string company { get; set; }
      public string address_line_1 { get; set; }
      public string address_line_2 { get; set; }
      public string city { get; set; }
      public string state { get; set; }
      public string postal_code { get; set; }
      public string country { get; set; }
      public string phone { get; set; }
      public string fax { get; set; }
      public string email { get; set; }
    }

    public class Data
    {
      public string id { get; set; }
      public string type { get; set; }
      public int amount { get; set; }
      public int tax_amount { get; set; }
      public bool tax_exempt { get; set; }
      public int shipping_amount { get; set; }
      public int discount_amount { get; set; }
      public string payment_adjustment_type { get; set; }
      public int payment_adjustment_value { get; set; }
      public string currency { get; set; }
      public string description { get; set; }
      public string order_id { get; set; }
      public string po_number { get; set; }
      public string ip_address { get; set; }
      public bool email_receipt { get; set; }
      public string email_address { get; set; }
      public string payment_method { get; set; }
      public Response response { get; set; }
      public string status { get; set; }
      public int response_code { get; set; }
      public string customer_id { get; set; }
      public BillingAddress billing_address { get; set; }
      public ShippingAddress shipping_address { get; set; }
      public DateTime created_at { get; set; }
      public DateTime updated_at { get; set; }
    }

    public class RootObject
    {
      public string status { get; set; }
      public string msg { get; set; }
      public Data data { get; set; }
    }
  }
}

Here is my code so far:

private void button1_Click(object sender, EventArgs e)
{
  var urlx = "https://xxxxx.xxxxxxx.com/api/";
  var usr = "xxxxxxxxxxx";
  var pwd = "xxxx";

  // replace with the TEST class to pass in the required JSON request
  // BaSysRequest item = new BaSysRequest();
  // item.username = usr;
  // item.password = pwd;

  string request = JsonConvert.SerializeObject(item);

  Uri url = new Uri(string.Format(urlx));

  string response = Post(url, request);

  if (response != null)
  {
    Console.WriteLine(response);
  }
  else
  {
    Console.WriteLine("nothing");

  }

}


public string Post(Uri url, string value)
{
  var request = HttpWebRequest.Create(url);
  var byteData = Encoding.ASCII.GetBytes(value);
  request.ContentType = "application/json";
  request.Method = "POST";

  try
  {
    using (var stream = request.GetRequestStream())
    {
      stream.Write(byteData, 0, byteData.Length);
    }
    var response = (HttpWebResponse)request.GetResponse();
    var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

    return responseString;
  }
  catch (WebException e)
  {
    return null;
  }
}

public string Get(Uri url)
{
  var request = HttpWebRequest.Create(url);
  request.ContentType = "application/json";
  request.Method = "GET";

  try
  {
    var response = (HttpWebResponse)request.GetResponse();
    var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();

    return responseString;
  }
  catch (WebException e)
  {
    return null;
  }
}

How do I populate the ApiRequest and pass in the class? Did I create the class correctly for the json data?

Any suggestion?


Solution

  • Since the payment method can be different types then take advantage of using generics

    public class TransactionRequest<T> {
        public string type { get; set; }
        public long amount { get; set; }
        public long tax_amount { get; set; }
        public long shipping_amount { get; set; }
        public string currency { get; set; }
        public string description { get; set; }
        public string order_id { get; set; }
        public string po_number { get; set; }
        public string ip_address { get; set; }
        public bool email_receipt { get; set; }
        public string email_address { get; set; }
        public bool create_vault_record { get; set; }
        public Dictionary<string, T> payment_method { get; set; }
        public Address billing_address { get; set; }
        public Address shipping_address { get; set; }
    }
    
    public class Address {
        public string first_name { get; set; }
        public string last_name { get; set; }
        public string company { get; set; }
        public string address_line_1 { get; set; }
        public string address_line_2 { get; set; }
        public string city { get; set; }
        public string state { get; set; }
        public string postal_code { get; set; }
        public string country { get; set; }
        public string phone { get; set; }
        public string fax { get; set; }
        public string email { get; set; }
    }
    

    The above class is based on the example request made in the original question.

    For each one of the possible payment types create a matching model definition that can be used with the generic type

    Like Card for example

    public partial class Card {
        public string entry_type { get; set; }
        public string number { get; set; }
        public string expiration_date { get; set; }
        public long cvc { get; set; }
        public CardholderAuthentication cardholder_authentication { get; set; }
    }
    
    public partial class CardholderAuthentication {
        public string condition { get; set; }
        public string eci { get; set; }
        public string cavv { get; set; }
        public string xid { get; set; }
    }
    

    From there it is just a matter of constructing the request and posting to the desired URL

    For example

    static Lazy<HttpClient> client = new Lazy<HttpClient>();
    
    private async void button1_Click(object sender, EventArgs e) {
        var urlx = "https://xxxxx.xxxxxxx.com/api/";
        var usr = "xxxxxxxxxxx";
        var pwd = "xxxx";
    
        Card card = new Card();
        //populate as needed
    
        TransactionRequest<Card> item = new TransactionRequest<Card>();
        //populate as needed
    
        //set payment method accordingly
        item.payment_method["card"] = card;
    
        Uri url = new Uri(string.Format(urlx));
    
        string response = await PostAsync(url, item);
        if (response != null) {
            Console.WriteLine(response);
        } else {
            Console.WriteLine("nothing");
        }
    }
    
    public async Task<string> PostAsync<T>(Uri url, T value) {
        try {
            string json = JsonConvert.SerializeObject(value);
            var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
            var response = await client.Value.PostAsync(url, content);
            var responseString = await response.Content.ReadAsStringAsync();
            return responseString;
        } catch (Exception e) {
            //TODO: log error
            return null;
        }
    }