NAV Consume Webservice Black-Belt

Often a small assignment turns out to be somewhat more….

Also this time the question was simple.
“Please develop some code that calls this webservice, the information is at the providers site, use JSON”.

so I went to the providers’ site and found some documentation:

API Specs

Apparently : need to Use X-APIKEY request header to identify myself. And I can test my apikey with this API Call:

GET //v1/transaction HTTP/1.1
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8,nl;q=0.6
Connection:keep-alive
Host:api.spryngpayments.com
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36
X-APIKEY:zJqFMRBDT8BPgkPO81UC0js2TWoFK

So I started with a test codeunit :

4 variables: (all on server)

HTTPWebRequest - System.Net.HttpWebRequest.'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
HTTPWebResponse- System.Net.HttpWebResponse.'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
Streamreader - System.IO.StreamReader.'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
String  : Text[1024]

one-function “Do-IT”

HttpWebRequest := 
    HttpWebRequest.Create(https://sandbox.spryngpayments.com/v1/api_key'');
HttpWebRequest.Method := 'GET';
HttpWebRequest.ContentType('application/json');
HttpWebRequest.Headers.Add('X-APIKEY','my ApiKey');
HttpWebResponse := HttpWebRequest.GetResponseAsync.Result;
StreamReader := StreamReader.StreamReader(HttpWebResponse.GetResponseStream);
String := StreamReader.ReadToEnd;
HttpWebResponse.Close();
MESSAGE(String);

And go!

KaBooommmmm

this is a no go! an Ugly error appears:

An existing connection was forcibly closed by the remote host

hmm what to do…

Tried a bunch of things:

  • ask the provider –> should work, no clue
  • search on mibuso –> nope
  • add an issue on mibuso  this is the issue
  • use an alternative app ( Postman – the perfect tool for testing RESTAPI and more)
  • changed to HTTP  –> Got a permanent redirect ( to the HTTPS)
  • tried another REST API –> works like a charm  (try it yourself here)
  • tried another api with HTTPS –> works perfectly

No luck following these paths. Need to have a root cause, in order to find a solution.

So I used Fiddler , a great tool to sniff your network traffic. Installed on my system and go.

B*mmm .. no trace of the NAV webcall.

Found out this is since NAV is running as service and the service needs to be informed to reroute all package through fiddler.

This is done like this:

  1. Go to : C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config
  2. locate the file machine.config.
  3. open the file (first create a backup)
  4. locate the section <system.net>  (or create this section at the bottom , within configuration tag).
    Update the section to:

      <!-- The following section is to force use of Fiddler for all 
           applications, including those running in service accounts -->
      <system.net>
         <defaultProxy
            enabled = "true"
            useDefaultCredentials = "true">
            <proxy autoDetect="false" bypassonlocal="false" 
                proxyaddress="http://127.0.0.1:8888" 
                usesystemdefault="false" />
          </defaultProxy>
      </system.net>
  5. Restart NAV Service tier.
  6. (do not forget to remove this section (use the backup from step 3) and restart NAV after sniffing.

This made the NAV calls visible within Fiddler! ( and added a blog)

After some sniffing between the Postman’s successful calls and the NAV unsuccessful call the root cause became clear:

The problem was caused during establishing the HTTPS connection :

Postman ( success):

A SSLv3-compatible ClientHello handshake was found. Fiddler extracted the parameters below.

Version: 3.3 (TLS/1.2)
Random: 42 86 E5 DA 44 4D E2 F8 B6 BF 4F B6 1E D1 C0 CA F3 85 F2 D3 BF B4 06 AF 46 75 D4 17 20 0E EB 53
Time: 17/05/2086 14:00:02
SessionID: empty

NAV (failure)

A SSLv3-compatible ClientHello handshake was found. Fiddler extracted the parameters below.

Version: 3.1 (TLS/1.0)
Random: 58 B4 37 85 AE 5F 31 3F AF 51 2D EC C5 BB CF B9 86 59 95 9E 30 BA 14 F1 FA 63 B3 5A 12 DB 60 C2
Time: 28/10/2040 07:59:36
SessionID: empty

A Different type of HTTPS was used.

Apparently the API required a higher level of security than my call was offering.

Googled my way into this difference and found that it is a .NET 4.5 feature to use TLS/1.2, however this is turned off by default.

Needed to  add only one line of code and 2 variables.

ServicePointManager :
 [System.Net.ServicePointManager.'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089']
SecurityProtocol :
[System.Net.SecurityProtocolType.'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089']

Working code:

ServicePointManager.SecurityProtocol := SecurityProtocolType.Tls12;//FIX
HttpWebRequest := 
    HttpWebRequest.Create(https://sandbox.spryngpayments.com/v1/api_key'');
HttpWebRequest.Method := 'GET';
HttpWebRequest.ContentType('application/json');
HttpWebRequest.Headers.Add('X-APIKEY','my ApiKey');
HttpWebResponse := HttpWebRequest.GetResponseAsync.Result;
StreamReader := StreamReader.StreamReader(HttpWebResponse.GetResponseStream);
String := StreamReader.ReadToEnd;
HttpWebResponse.Close();
MESSAGE(String);

And the result:

new-bitmap-image

Mission accomplished!