Sample code for C#

On this page you will find a very simplistic sample on how to post a score to KPI Dashboard using our API.

HTTP 417 – Expectation Failed

It seems that this error can also occur on some proxies that don’t support “100 continue” expectation. The workaround is to add the following to the .exe.config file.

<configuration>
  <system.net>
    <settings>
      <servicePointManager expect100Continue="false" />
    </settings>
  </system.net>
</configuration>

See also: http://social.msdn.microsoft.com/Forums/en-US/devdocs/thread/60cd6e6a-4157-4811-8ed3-1e46f9022ea8

WCF REST Starter Kit

The example below uses a simple REST client implemented in the “Send” method. As replacement you might want to take a look at the HttpClient class which is part of Microsofts WCF REST Starter Kit

Getting user details, finding indicators, creating and deleting scores

Download this sample code.

using System;
using System.Collections;
using System.Text;
using System.IO;
using System.Net;
using System.Web;
using System.Xml;

/// <summary>
/// This is an example how to use the KPI Dashboard API.
/// Language: C#
/// 
/// This sample code shows how to lookup an existing indicator
/// Then it creates a score for this indicator.
/// At the end it removes the created score again.
/// 
/// ------------------------------------------------------------------
/// You will need to adjust the MY_API_TOKEN value:
/// 
/// MY_API_TOKEN - Your API token, as displayed on your
///                "Personal Settings" page in KPI Dashboard.
/// ------------------------------------------------------------------
/// 
/// Feel free to use this code and modify to fit your needs.
/// For more information visit http://dashboard.kpilibrary.com/api
/// 
/// ------------------------------------------------------------------
/// </summary>
public class ApiSample
{
    /// <summary>
    /// Replace the info below with your own:
    /// MY_API_TOKEN = "find-your-key-in-your-personal-settings-page"
    /// </summary>
    public static readonly string MY_API_TOKEN = "FILL IN YOUR TOKEN HERE";

    public static readonly string API_URI = "https://dashboard.kpilibrary.com/api/v2";

    public enum HttpMethod { GET, POST, PUT, DELETE }

    /// <summary>
    /// Get my user info from KPI Dashboard.
    /// </summary>
    /// <returns>list of { [user], [tenant], [role] }</returns>
    public static ArrayList GetMyUserDetails()
    {
        Uri uri = new Uri(API_URI + "/me.xml");
        string response = Send(uri, HttpMethod.GET, null);
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(response);
        XmlElement root = doc.DocumentElement;
        if (root.HasChildNodes)
        {
            XmlNodeList nodes = root.SelectNodes("user");
            System.Collections.IEnumerator ienum = nodes.GetEnumerator();
            ArrayList userDetails = new ArrayList();
            while (ienum.MoveNext())
            {
                XmlNode n = (XmlNode)ienum.Current;
                string name = n.SelectSingleNode("name").InnerText;
                string tenant = n.SelectSingleNode("tenant-name").InnerText;
                string role = n.SelectSingleNode("role").InnerText;
                userDetails.Add(new string[] { name, tenant, role });
            }
            return userDetails;
        }
        else
        {
            throw new Exception("Error: Invalid response when getting user info.");
        }
    }

    /// <summary>
    /// Gets a list of indicators from KPI Dashboard. For demo purposes
    /// we simply return the 1st indicator from this list.
    /// </summary>
    /// <returns>array { [indicator id], [indicator name] } </returns>
    public static string[] GetFirstIndicator()
    {
        Uri uri = new Uri(API_URI + "/indicators.xml");
        string response = Send(uri, HttpMethod.GET, null);
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(response);
        XmlElement root = doc.DocumentElement;
        if (root.HasChildNodes)
        {
            // for this demo get the first indicator //
            XmlNode n;
            n = root.FirstChild.SelectSingleNode("id");
            string indicatorId = n.InnerXml;
            n = root.FirstChild.SelectSingleNode("name");
            string indicatorName = n.InnerXml;
            return new string[] { indicatorId, indicatorName};
        }
        else
        {
            throw new Exception("Error: No indicators are defined in KPI Dashboard. Try loading the demo data.");
        }
    }

    /// <summary>
    /// Add a socre to an indicator in KPI Dashboard
    /// </summary>
    /// <param name="indicatorId">ID of the indicator to add to score to. <see>ApiSample.GetFirstIndicator()</see></param>
    /// <param name="value">The value of the score</param>
    /// <param name="date">The date of the score in format YYYY-MM-DD</param>
    /// <returns></returns>
    public static string PostScore(string indicatorId, string value, string date)
    {
        Uri uri = new Uri(API_URI <notextile><code> "/indicators/" </code></notextile> indicatorId + "/scores.xml");
        StringBuilder xml = new StringBuilder();
        xml.Append("<score><value>").Append(value).Append("</value><date>").Append(date).Append("</date></score>");
        string response = Send(uri, HttpMethod.POST, xml.ToString());
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(response);
        XmlElement root = doc.DocumentElement;
        if (root.HasChildNodes)
        {
            XmlNode n = root.SelectSingleNode("id");
            string scoreId = n.InnerXml;
            return scoreId;
        }
        else
        {
            throw new Exception("Error: Invalid response when posting score.");
        }
    }

    /// <summary>
    /// Delete a score from KPI Dashboard
    /// </summary>
    /// <param name="scoreId">ID of the score. <see>ApiSample.PostScore()</see></param>
    public static void DeleteScore(string scoreId)
    {
        Uri uri = new Uri(API_URI <notextile><code> "/scores/" </code></notextile> scoreId + ".xml");
        Send(uri, HttpMethod.DELETE, null);
    }

    /// <summary>
    /// Communicate with the KPI Dashboard API.
    /// </summary>
    /// <param name="uri">URI of the API to interact with</param>
    /// <param name="method">The HTTP method to be used <see>ApiSample.HttpMethod</see></param>
    /// <param name="data"></param>
    /// <returns></returns>
    private static string Send(Uri uri, HttpMethod method, string data)
    {
        string PASSWORD = "ignored";
        try
        {
            // Create the web request  
            HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;

            //This line ensures the request is processed through Basic Authentication
            request.Credentials = new NetworkCredential(MY_API_TOKEN, PASSWORD);
            request.Method = Enum.GetName(typeof(HttpMethod), method);

            switch (method)
            {
                case HttpMethod.GET:
                    break;
                case HttpMethod.PUT:
                case HttpMethod.POST:
                    if (string.IsNullOrEmpty(data)) throw new Exception("Error: HttpMethod POST needs data to send");
                    request.ContentType = "application/xml;charset=utf-8";
                    data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + data;
                    Stream s = request.GetRequestStream();
                    s.Write(System.Text.Encoding.ASCII.GetBytes(data), 0, data.Length);
                    s.Close();
                    break;
                case HttpMethod.DELETE:
                    break;
            }

            WebResponse response = request.GetResponse();
            StreamReader sr = new StreamReader(response.GetResponseStream());
            string xml = sr.ReadToEnd();
            //Console.WriteLine("Response from KPI Dashboard:\n{0}\n\n", xml);
            return xml;
        }
        catch (WebException we)
        {
            StreamReader sr = new StreamReader(we.Response.GetResponseStream());
            string errorMsg = sr.ReadToEnd();
            throw new Exception(we.Message <notextile><code> " " </code></notextile> errorMsg, we);
        }
    }

    /// <summary>
    /// Example code
    /// - shows user details
    /// - fetches the 1st indicator
    /// - posts score of the indicator
    /// - removes the socore again
    /// </summary>
    /// <param name="args"></param>
    static void Main(string[] args)
    {
        try
        {
            Console.WriteLine("Getting my user info ...");
            ArrayList userDeatils = GetMyUserDetails();
            foreach (string[] userDetail in userDeatils)
            {
                Console.WriteLine("{0} has access to {1} as {2}", userDetail[0], userDetail[1], userDetail[2]);
            }

            Console.WriteLine("Selecting first indicator ...");
            string[] indicator = GetFirstIndicator();
            string indicatorId = indicator[0];
            string indicatorName = indicator[1];
            Console.WriteLine("Selected Indicator \"{0}\" with id {1}", indicatorName, indicatorId);

            Console.WriteLine("Creating score ...");
            string scoreId = PostScore(indicatorId, "33.39", "2010-09-30");
            Console.WriteLine("Created score {0}", scoreId);

            Console.WriteLine("Deleting score ...");
            DeleteScore(scoreId);
            Console.WriteLine("Deleted score.");

            Console.WriteLine("Done.");
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
        Console.WriteLine("\nPress any key close this application");
        Console.ReadLine();
    }
}

Download this sample code.