Exposing Dynamics NAV data to my iPhone

In the past days I have build a small iOS App that talks to my Navision API Service (further referred to as API). The API acts like a proxy service between Dynamics NAV and the rest of the world and could be accessed by many different Apps and devices. The API is able to consume data that is published as a web service from Dynamics NAV and publish this data to others:

Infrastructure

The reason why this infrastructure is needed is that you cannot allow anyone to communicate directly to your Dynamics NAV server from a connected device. However this is not what I am focusing on in this post, I am also not the infrastructural and security expert. It is just about the code. This is no advise, just my current Lab setup:

Any Connected Device: this can be any connected device on the Internet, capable of communicating through HTTP(S), this device should authenticate with the Navision API Service with a security token. Right now it is my iPhone simulator.

Navision API Service: this service runs as a webservice and listens to one single port. Only predefined services can be called by authenticated Apps. The API authenticates itself with a restricted service account to Dynamics NAV.

Dynamics NAV Web Service: this is the Dynamics NAV Service Tier: for the web services it listens to port 7047 and is setup to use NTLM authentication.

Setting Up Dynamics NAV 2015

For this example I have published a page “CustomerListWS”. The page will show all customers and publishes the following information about the customer:

Customer List Page Design

The page is published as a web service in the Web Services Page:

Customer List Web Service

That is all. The published web services can now be queried through HTTP by clients using NTLM authentication.

The API will authenticate and query the webservice like this:

http://mydomain/DynamicsNAV80/OData/Company(‘CRONUS Nederland BV’)/CustomerListWS?$format=json

Setting up the API to Consume from Dynamics NAV

Like the Dynamics NAV web service, the API will also act as a web service. The API must be capable of doing three things:

  1. Wait and listen for valid/authenticated API requests
  2. Consume the data from Navision
  3. Return data to requester or send back an error.

That should be all and can be covered in a few functions. The API is build in Xojo and could run as a stand alone server on a Windows, Mac or Linux machine.

Listening for API requests:
The API acts like a webserver and waits for a call to a specific URL which it will then try to serve. Xojo Web has a very nice Event Handler specially written for this. Suppose we need an event handler for returning a list of all customers, we could use a name like “GetAllCustomers” for that. Than if the requesting party would use the URL “http://mydomain:8080/api/GetAllCustomers” the API would execute code the in the event handler that is called “HandleSpecialURL”. In the code we can ‘catch’ the request and act upon that.

In this case “GetAllCustomers” does the job to execute a method with the same name that does all the work for us. At the end of the event handler we return JSON data to the requesting party:

Function HandleSpecialURL(Request As WebRequest) As Boolean
  Dim data As Text = DefineEncoding(Request.Entity, Encodings.UTF8).ToText
  Dim json As JSONItem
  
  Select Case Request.Path
    
  Case "GetAllCustomers"
    json = GetAllCustomers // This method queries Navision and returns information from all customers
  Case Else
    // Do nothing, maybe a wrong URL has been used
    Return False
  End Select
  
  // Send back the requested data
  Request.Print(json.ToString)
  
  Return True
End Function

Querying Navision and packaging JSON data
The method GetAllCustomers queries Dynamics NAV and will de-serialize the received data and put it into a nice and clean JSON package to be returned to the requesting party.

Private Function GetAllCustomers() As JSONItem
  Dim c As New CURLSMBS
  Dim cresult As Integer
  Dim URL As String
  Dim UrlPart(3) As String
  
  // Get URL parts together, we need URL encoding
  UrlPart(0) = "http://hp-jacco:7048/DynamicsNAV80/OData"
  UrlPart(1) = "Company('CRONUS Nederland BV')"
  UrlPart(2) = "CustomerListWS"
  
  // Compose the URL form the Url parts en URL encode the parts
  URL = UrlPart(0) + "/" + EncodeURLComponent(UrlPart(1)) + "/" + EncodeURLComponent(UrlPart(2)) + "/?$format=json"
  
  // Authenticate with NTLM and do request with CURL
  c.OptionVerbose = True
  c.OptionURL = URL
  c.CollectOutputData = True
  c.OptionHTTPAuth = 8
  c.OptionUsername = "[domain\user]" // Must be a valid user with sufficient rights for Dynamics NAV
  c.OptionPassword = "[password]"
  cresult = c.Perform
  
  // Parse json
  Dim jsonData As String = c.OutputData
  Dim results As New JSONItem(jsonData)
  Dim navisionData As JSONItem = results.Value("value")
  
  // Put data in a new JSON item to return
  Dim jsonCustomers As New JSONItem
  Dim cust As New Dictionary
  
  // Make a nice JSON package
  Dim i As Integer
  For i = 0 To navisionData.count-1
    Dim navisionItem As JSONItem = navisionData.child(i)
    cust = New Dictionary
    cust.Value("No") = navisionItem.value("No").StringValue
    cust.Value("Name") = navisionItem.value("Name").StringValue
    cust.Value("Address") = navisionItem.value("Address").StringValue
    cust.Value("Address_2") = navisionItem.value("Address_2").StringValue
    cust.Value("Post_Code") = navisionItem.value("Post_Code").StringValue
    cust.Value("City") = navisionItem.value("City").StringValue
    cust.Value("Country_Name") = navisionItem.value("Country_Name").StringValue
    
    jsonCustomers.Value(navisionItem.value("No").StringValue) = cust
  Next
  
  Dim jsonResults As New JSONItem
  jsonResults.Value("GetAllCustomers") = jsonCustomers
  
  // Return the data
  Return jsonResults
End Function

Is that all?
Basically, yes, but note that for every extra Navision item, like Contacts, Vendors, Orders, Items and so on, extra code is required in the HandleSpecialURL event handler, also additional methods have to be made to request the data and package up in JSON and return it. In order to keep this code readable I left out authentication to the API, errorhandling and encoding stuff and I have not done any code optimization.

Getting the Data from Navision on my Iphone

iOS App development is quite another story in terms of easy coding. I find this not so easy to do and I am still trying to find my way in Xojo on how to do this from scratch. Xojo provides an excellent example of an iOS App that interacts with a Sqlite database. From this example and from a couple of Xojo webinars I learned enough to fabricate my own App that connects with my Navision API.

Describing the whole App development process would be way too much to cover in one post, I will only show you the end result in this post. Maybe later I will write more about App development but at this stage I am still learning a lot myself:

NAvision and iPhone 6

As you can see the data from the  ‘Cronus’ database (NL version) shows nicely in my iPhone App:-)

The iOS testing & debugging was done on a remote Macbook Pro. From the moment the data was requested from the iOS App, to the moment the data was parsed and put into place in the iPhone simulator took less than a second. The JSON format proves to be very suitable for these kinds of applications. JSON files are appr. 25% smaller than XML and therefore excellent for low bandwidth environments.

Conclusion

It is always great when an idea comes alive like this. I learned a lot of techniques in just a few days. Next time I will try to build the same iOS App in Xcode, with Swift, just to discover the differences with Xojo for iOS and learn from it. And for more fun of course because than I would be interacting between Dynamics NAV, Xojo and Xcode applications:-)

 

 

 
Comments
 
Comments

No comments yet.