2015-01-11

Simpro & SSIS Part 1: Access Simpro through OAuth


Back to mid of 2014, one of our clients started to use a job management system, Simpro (Simpro.com.au), to run its business. On base of that, what they need is a data procedure to extract, transform, and report Simpro activities with other datasets, for example, contact center activities and dialler performance.

As there was no fast way to integrate a dialler into the system, we decided to download Simpro activities through its APIs. My basic idea is:
  • Extract Simpro data into staging area via SSIS Script task
  • Extract Dialler data into staging area via SSIS package, as it can be done through ADO.Net source
  • Cleansing and load into production

Simpro is a market leading job management system. However you may have the same feeling like me if you look at its API documentation: they are not well prepared. And if you do the Google research, you do not have too many reference materials.

So this is the reason I write this series: to record what I did in the project, start from the planning, to end of the implementation. And I hope this series can help you, if you need to find some Simpro API references.

To access Simpro we need to use OAuth, which you can find quite a lot references online. And you can find the specific guideline for Simpro at http://api.simpro.co/. However they are not provided in .Net implementation. As I am not a coding expert, I used below two components in my design:

OAuthBase.cs
You can find it at https://oauth.googlecode.com/svn/code/csharp/OAuthBase.cs. As name suggested, it is the base to implement OAuth access in .Net code.
Updated on 02/10/2017, please use below link to get OAuthBase:
https://gist.github.com/tsupo/112124

Json.Net
An optional but handy component to parse JSON string. You can find it at http://james.newtonking.com/json.

So too much talk, let’s look at some codes. Below codes are used to do a query against Simpro's Customer entitty. Hope it gives you some ideas before my next post: SSIS script task for Simpro.

(note, it is my understanding that in most Simpro APIs CompanyID is the only parameter required)

 public string GetJasonString(string ConsumerKey, string ConsumerSecret, string Url)  
     {  
       string JasonBuffer = "";  
       //build signiture  
       OAuthBase oAuth = new OAuthBase();  
       string nonce = oAuth.GenerateNonce();  
       string timeStamp = oAuth.GenerateTimeStamp();  
       string normalisedUrl;  
       string normalisedRequestParams;  
       string signature = oAuth.GenerateSignature(new Uri(Url), ConsumerKey, ConsumerSecret, null, null, "POST", timeStamp, nonce, out normalisedUrl, out normalisedRequestParams);  
       signature = HttpUtility.UrlEncode(signature);  
       //parameter  
       StringBuilder sb = new StringBuilder("");  
       sb.AppendFormat("OAuth oauth_version=\"1.0\",");  
       sb.AppendFormat("oauth_nonce={0},", nonce);  
       sb.AppendFormat("oauth_timestamp={0},", timeStamp);  
       sb.AppendFormat("oauth_consumer_key={0},", ConsumerKey);  
       sb.AppendFormat("oauth_signature_method=\"HMAC-SHA1\",");  
       sb.AppendFormat("oauth_signature={0}", signature);  
       WebClient Client = new WebClient();  
       Client.Headers.Add("Authorization", sb.ToString());  
       Client.Headers.Add("Content-Type", "application/json");  
       Client.Headers.Add("Accept", "application/json");  
       Client.Proxy = null;  
       JavaScriptSerializer JSS = new JavaScriptSerializer();        
       Dictionary<string, object> Params = new Dictionary<string, object>();  
       //CustomerSearch parameters  
       Params.Add("CompanyID", 0);  
       Params.Add("Search", "%");  
       Params.Add("Limit", 500);  
       Params.Add("Offset", 2000);  
       string Command = JSS.Serialize(new Dictionary<string, object>  
       {  
         {"id", "1"},  
         {"method", "CustomerSearch"},  
         {"params", Params}  
       });  
       byte[] bytes = Encoding.UTF8.GetBytes(Command);  
       byte[] bytesbuffer = Client.UploadData(Url, "POST", bytes);  
       JasonBuffer = Encoding.Default.GetString(bytesbuffer);  
       return JasonBuffer;  
     }  

6 comments :

  1. As part of the Simpro Authorisation you need to fill out a form. One of the fields on the form is Application URI. I am confused about the use of this field. Can you elaborate on what it is and the value you used?

    ReplyDelete
  2. Hi David

    If you are working on Simpro APIs, the application URI is the API access point. In Simpro's documentation, it is

    https://buildname.simpro.co/api/?format=(soap|json|xml)

    In my case, it is http://MyClientURL/api/?format=json

    ReplyDelete
  3. Hi David
    Can you please share the relevant code for Simpro API using c#

    As in this i am not able to get below code from google
    https://oauth.googlecode.com/svn/code/csharp/OAuthBase.cs

    Please share me on my email unitedit4@gmail.com

    ReplyDelete
    Replies
    1. Hi mate

      Thanks for pointing out the dead link. Please try updated link@github. Let me know if it doesn't work.

      Delete
    2. Thank you.
      One more thing i have tried with this and working with webclient.

      but i need to do it with httpclient not webclient. reason is i am using asp.net core 1.1

      below is my code

      string Url = SimproBaseUrl + "api/index.php";
      string JasonBuffer = string.Empty;

      OAuthBase oAuth = new OAuthBase();
      string nonce = oAuth.GenerateNonce();
      string timeStamp = oAuth.GenerateTimeStamp();
      string normalisedUrl;
      string normalisedRequestParams;
      string signature = oAuth.GenerateSignature(new Uri(Url), ConsumerKey, null, ConsumerSecret, null, null, "POST", timeStamp, nonce, out normalisedUrl, out normalisedRequestParams);
      signature = WebUtility.UrlEncode(signature);

      StringBuilder sb = new StringBuilder(Url);
      sb.AppendFormat("?oauth_version=1.0&");
      sb.AppendFormat("oauth_nonce={0}&", nonce);
      sb.AppendFormat("oauth_timestamp={0}&", timeStamp);
      sb.AppendFormat("oauth_consumer_key={0}&", ConsumerKey);
      sb.AppendFormat("oauth_signature_method=HMAC-SHA1&");
      sb.AppendFormat("oauth_signature={0}", signature);

      HttpClient client = new HttpClient();
      client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));//ACCEPT header
      Uri uri = new Uri(sb.ToString());

      try
      {
      string Command = string.Empty;
      Dictionary Params = new Dictionary();
      switch (apiMethod)
      {
      case "CompanySearch":
      Command = JsonConvert.SerializeObject(new Dictionary
      {
      {"id", "0"},
      {"method", apiMethod}
      });
      break;
      default:
      break;
      }
      var response = await client.PostAsync(uri, new StringContent(Command, Encoding.UTF8, "application/json"));
      if (response.IsSuccessStatusCode)
      {
      JasonBuffer = await response.Content.ReadAsStringAsync();
      }
      return JsonConvert.DeserializeObject(JasonBuffer) ;
      //return JasonBuffer.GetModelSync();
      }
      catch (Exception ex)
      {
      return (T)Activator.CreateInstance(typeof(T));
      }

      in this it is giving me internal server 500 error

      but same is working with postman tool

      Delete
    3. Hi UnitedIT

      Sorry for late response. But unfortunately I do not have access to Simpro any more, so I cannot test your code now. But if my memory is correct, couple things you might need to have a look:

      string Url = SimproBaseUrl + "api/index.php";

      The initial request address should be The simPRO API has one main access point: https://buildname.simpro.co/api/?format=json


      string signature = oAuth.GenerateSignature(new Uri(Url), ConsumerKey, null, ConsumerSecret, null, null, "POST", timeStamp, nonce, out normalisedUrl, out normalisedRequestParams);

      I am not sure which version of OAuthBase you are using, but it is just uncommon to have ConsumerKey and ConsumerSecret separated by another parameter? Is it a typo?

      Delete