If you are a developer or consultant who works for a modern Business Central-project that includes the integration of 3rd party services – you might come across this error while using HttpClient. Find out in this article why it happens, what do to about it and in which situation you have to live with it.
It took me quite a while to identify the circumstances under which this error occurs. First I thought that the error is related to settings in the ServiceTier. Because when running the same code to send a Http-request to a different endpoint, the request was successful. On a side note, I can recommend Pipedream to analyse the content and structure of an API-call sent from Business Central. Anyway, another reason why I thought it would be a problem in the ServiceTier is, that a simple ServiceTier restart fixes the error seemingly. But only until …
The root of all evil
.. the IP-address in the local DNS cache doesn’t match IP-address of the API-endpoint again. Modern API-endpoints sit behind a service like Cloudflare. The reason for this are security considerations (e.g. protection against DDoS). Services like Cloudflare assign multiple IPs to a DNS-name. And, each time a new IP is assigned to a DNS name – HttpClient will throw the error “An error occurred while sending the request.”
Reason for this behaviour is, that HttpClient utilizes the DotNet-Framework which maintains a local DNS cache. The background of such solution is to speed up reoccurring connections. A quick online research unfolds, that this is a common problem in the DotNet-world and needs attention in the code: https://stackoverflow.com/questions/7277582/how-do-i-clear-system-net-client-dns-cache
Reading the thread in Stackoverflow, two solutions are proposed that can be integrated easily. The first solution is to set the property “KeepAlive” to false. This instructs the application to close any Http-connection and establish a new connection each time the code runs. This includes a new lookup of the IP-address behind a DNS name.
The other option is to set the property “ConnectionLeaseTimeout”. Using this property it is possible to keep connections alive for a certain amount of time. This solution could be used, when the application would automatically retry to send a request, when an error occurrs. You can find more information here: https://docs.microsoft.com/en-us/dotnet/api/system.net.servicepoint.connectionleasetimeout?view=netcore-3.1
Solutions – yes, but with limitations
You can integrate both solutions using AL. I’m using the “KeepAlive”-solution in my projects and it works fine with API-endpoints sitting behind services like Cloudflare. Using the “KeepAlive”-solution it is necessary to switch from HttpClient- to HttpWebRequest-Class. Unfortunately, the “KeepAlive”-property is not available through the HttpClient-Class. (source)
Although the HttpWebRequest-Class is available as DotNet-Datatype in Business Central by default. The ServicePoint-Class is not available and it would be necessary to declare the DotNet-package to make it available.
But, the problem lies in the limitations of Extension-development. As long as you can set the target of your Extension to “OnPrem”, you don’t have a problem. But, when your Extension is targeted for the cloud – you have a problem without solution.
Here is an example how to utilize the ConnectionLeaseTimeout-solution in AL. This option is easier to integrate as it is possible to keep the code that utilizes the HttpClient-class.
Below screenshot shows the declaration of the DotNet class.
These DataTypes are needed.
And here is the code.
In all my projects, I tend to use “HttpWebRequest”-class as my default. If you go this route, you will not have any problems.