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:
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:
The page is published as a web service in the Web Services Page:
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:
- Wait and listen for valid/authenticated API requests
- Consume the data from Navision
- 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:
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.
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:-)