Wednesday, October 20, 2010

Consuming Advantage Web API Results

As I discussed in my last post the Advantage Web API returns data using JSON in a format based on the oDATA Protocol Standard. In order to use this data it needs to be transformed into an object that the client can work with. Let's begin by looking at a sample of the data returned from the Advantage Web API. I Included only a single record in the sample and I included the additional information ( rows_affected and last_autoinc ) which will be returned with each request.

{
  "d": {
    "results": [
      {
        "__metadata": {
          "uri": "https://Server.localdomain:6282/adsweb/example/v1/query/select * FROM customer"
        },
        "CustID": "c50585b4-b039-4843-a092-ef00da72bb90",
        "CustNum": 10000,
        "LastName": "Martin",
        "FirstName": "Denise",
        "Gender": "F",
        "CompanyID": 446,
        "CustomerSince": "1953-10-08",
        "Address1": "16907 HERITAGE COURT",
        "Address2": null,
        "City": "Wolf Point",
        "State": "MT",
        "ZipCode": "59201",
        "CellPhone": "(555) 555-4289",
        "WorkPhone": "(555) 555-9415"
      },
    ],
    "__next": "https://Server.localdomain:6282/adsweb/example/v1/query/select%20*%20FROM%20customer?$skiptoken=21"
  },
  "__metadata": {
    "rows_affected": -1,
    "last_autoinc": 0
  }
}

The curly braces ( {} ) are used to distinguish objects within the string. The brackets ( [] ) are used to indicate arrays. Therefore the rows are defined within the results array. JSON serializers can be used to deserialize this into an object as long as the object conforms to the data provided in the string. Additionally we need to have a list of the object since the results object is an array of the rows. The object and list are defined below:

// definition of Customer fields
public class Customer
{
   public string CustID;
   public int CustNum;
   public string LastName;
   public string FirstName;
   public string Gender;
   public int CompanyID;
   public DateTime CustomerSince;
   public string Address1;
   public string Address2;
   public string City;
   public string State;
   public string ZipCode;
   public string CellPhone;
   public string WorkPhone;
}

// List of customers 
public class CustomerRows : List { }

The serializer will copy the information from the results array into the two objects defined above. The values will be assigned based on the names defined in the JSON so the types defined in the class must have exactally the same names. These classes must be defined for each table or query that you want to receive.

There are a few more classes that we need to define to handle the rest of the JSON string. We will still need classes to handle the d and the final metadata information. Unlike the classes mentioned above these classes can be reused for any JSON object. These objects are shown below:

// Processes the __metadata tag
public class oDataResults  // T needs to be a list of objects
{
   public DInfo d;
   public oQueryMeta __metadata;
}

// processes the results tag
public class DInfo
{
   public T results;
   public string __next;
}

// processes the final __metadata tag
public class oQueryMeta
{
   public int rows_affected;
   public int last_autoinc;
}

The first class ( oDataResults )determines the type that will be used when the results array is processed. The DInfo class allows the serializer to put the data into the specified type and gets the __next value. The oQueryMeta class gets the rows_affected and last_autoinc values.

With all of our classes defined all we need to do is send our request and process the results.

using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
  using (Stream dataStream = response.GetResponseStream())
  {
     using (StreamReader reader = new StreamReader(dataStream))
     {
       JsonSerializer serializer = new JsonSerializer();
       
       oDataResults oList;
       olist = (oDataResults)serializer.Deserialize(
				new JsonTextReader(reader), 
				typeof(oDataResults));
       
       // Bind the list of customer objects to a datagrid control   
       dgCustomer.DataSource = olist.d.results;
     }
  }
}

We will have more sample code available with the release of the Advantage Web API.

No comments: