This blog outlines the REST and JSON code used in the SysInfo Universal App that mimics the Web Portal to Windows 10 IoT devices. This portal is a web service running on the devices that permits examination of the aspects of a currently running system.


Project on GitHub: https://github.com/djaus2/IoTSysInfo

Original blog post on the app: Win 10-IoT: SysInfo: A Windows Universal App to get system info (as per the web portal)

Development Requirements: Windows 10, Visual Studio 2015 RTM, Windows 10 IoT device (eg Raspberry Pi 2)

Acknowledgement

The basis of this app (wrt REST and the Web Portal API) came for a blog by Bruce Eitman:

Windows 10 IoT Core: Getting the MAC Address from Raspberry Pi.

 

In the code blocks that follow, only an outline is shown. Inspect the actual project code to see the full implementation.

 

JSON

For an understanding of JSON visit http://json.org

A JSON object is a name-value pair.  The value can be a simple type, an object or an array of values (which can be a simple type, an object or an array …

 

An array is an ordered collection of values. 

A value can be a string in double quotes, or a number, or true or false or null, or an object or an array. These structures can be nested.

 

A REST call will return the JSON data as a textual string which can be parsed into .NET JSON class objects.

JSON String:

  • An object is an unordered set of name/value pairs.
  • An object begins with { (left brace) and ends with } (right brace).
  • Each name is followed by : (colon) and a value
  • Name/value pairs are separated by , (comma).
  • An array begins with [ (left bracket) and ends with ] (right bracket). Values are separated by , (comma).
  • As sample JSON string, a list of name value pairs (a SYSINFO call):
    {"DeviceModel" : "Raspberry Pi 2 Model B", "DeviceName" : "minwinpc", "OSVersion" : "10.0.10240"}	

Displays as:


image

 

REST API Calls

The REST calls use a URL made up of the target name or IPAddress, the port (8080) and an API path:

These API paths are of the form /api/Service/Info. There are determined by examining the JavaScript files that the various web port tab pages use.

The following are the APIs used in the app.

 

IpConfig

  /api/networking/ipconfig

SysInfo

  /api/iot/deviceinformation

OSAPI

  /api/os/info

Devices

  /api/devicemanager/devices

Processes

  /api/resourcemanager/processes

DefaulApp

  /api/iot/appx/getdefault

Providers

  /api/etw/providers

 

The method GetJsonStreamData takes one of these truncates URLs and generates the REST call to the IoT device’s portal web service:

GetJsonStreamData ()

        private static async Task<StreamReader> GetJsonStreamData(String URL)
        {            
//Form full REST url by joining Device(name or IPAddress) + :Port + URL
string url = "http://" + Device + ":" + Port +"/"+ URL;
try { //Set up REST call with the URL and Credentials (wrGetURL) //Make the REST call and await the response
HttpWebResponse Response = (HttpWebResponse)(await wrGETURL.GetResponseAsync());
if (Response.StatusCode == HttpStatusCode.OK) { //If OK then get reader to return: //Get the response stream from the response



//Get the reader from the response stream

}
}
catch()
{
}


//return the reader }

Outline of the REST call function

DoQuery()

Call the REST method GetJsonStreamData () (as above) with the command’s truncated URL.(Call GetJsonStreamData() )

Read the response stream as text..

Turn into a JSON object.

Parse the JSON object for Name-Value Pairs etc (Call GetNameValues() )

 
       public async static Task<bool>  DoQuery(string url)
        {       
            //Clear the list
//Do REST call for the command (as per the URL) StreamReader SR = await GetJsonStreamData(url); if (SR==null) { return false; } //Process the JSON stream data JsonObject ResultData = null; try { String JSONData; //Get the complete stream as text. //Convert to JSON object //Call GetNameValues() to recursively process the JSON data } catch (Exception ex) { return false; } return true; }

Outline of the Query  function.

 

GetNameValues()

 

Recursively get all name-value pairs in the object:

  • If value is an object call this function  recursively with the value
  • If value is an array get objects in array and recursively call this for each item in the array
  • Otherwise its value is a simple type So get its value and add to the list.
 
        public static void GetNameValues(JsonObject oJson)
        {
            foreach (Name-Vakue-Pair  in oJson)
            {
              //Get name-value-pair type as string
                if (typ == "object")
                {
                    //Recursively call this function with this name-value 
                }
                else if (typ == "array")
                {            
                    //Turn into array of JSON objects (ja)
                    //foreach JSON object in array (actually use indexed for loop)
                    for(uint index = 0; index < ja.Count; index++)
                    {
                        //Recursively call this function with each name-value in the array
                    }
                }
                else
                {
                    //Got a value to add to list
                    NameValue nv = new NameValue(oJson_KVP);
//Note: The NameValue constructor automatically adds new instances to the list } } }

Outline of the JSON parsing function

 

Simplifications in the code outlines:

Some aspects of code outlines above were simplifications. See the actual project code for details.

  1. With the actual implementation of GetJsonStreamData () cancellation and timeout of the request is included as part of the await call.
  2. Error catching is only partially shown.
  3. In parsing a JSON object symbols are added to the strings to be listed indicating they are just properties (with a .) or are part of an array (with –>)
    Also array items have a prepended index if there is more than item in the array.