/// <summary>
        /// Tries to parse the <see cref="Message.GetBytes"/> to a json representation of <see cref="LoRaCloudToDeviceMessage"/>.
        /// </summary>
        private void ParseMessage()
        {
            var bytes = this.message.GetBytes();

            if (bytes?.Length > 0)
            {
                var json = Encoding.UTF8.GetString(bytes);
                try
                {
                    this.parseCloudToDeviceMessage = JsonConvert.DeserializeObject <ReceivedLoRaCloudToDeviceMessage>(json);
                }
                catch (Exception ex) when(ex is JsonReaderException or JsonSerializationException)
                {
                    this.invalidErrorMessage = $"could not parse cloud to device message: {json}: {ex.Message}";
                }
            }
            else
            {
                this.invalidErrorMessage = "cloud message does not have a body";
            }
        }
        async Task <DecodePayloadResult> CallSensorDecoderModule(string devEUI, string sensorDecoderModuleUrl)
        {
            try
            {
                var httpClientToUse          = this.httpClient ?? this.decodersHttpClient.Value;
                HttpResponseMessage response = await httpClientToUse.GetAsync(sensorDecoderModuleUrl);

                if (!response.IsSuccessStatusCode)
                {
                    var badReqResult = await response.Content.ReadAsStringAsync();

                    return(new DecodePayloadResult()
                    {
                        Error = $"SensorDecoderModule '{sensorDecoderModuleUrl}' returned bad request.",
                        ErrorDetail = badReqResult ?? string.Empty,
                    });
                }
                else
                {
                    var externalRawResponse = await response.Content.ReadAsStringAsync();

                    if (!string.IsNullOrEmpty(externalRawResponse))
                    {
                        try
                        {
                            ReceivedLoRaCloudToDeviceMessage loRaCloudToDeviceMessage = null;
                            var externalDecoderResponse = JsonConvert.DeserializeObject <Dictionary <string, object> >(externalRawResponse);
                            if (externalDecoderResponse.TryGetValue(Constants.CLOUD_TO_DEVICE_DECODER_ELEMENT_NAME, out var cloudToDeviceObject))
                            {
                                if (cloudToDeviceObject is JObject jsonObject)
                                {
                                    loRaCloudToDeviceMessage = jsonObject.ToObject <ReceivedLoRaCloudToDeviceMessage>();
                                }

                                externalDecoderResponse.Remove(Constants.CLOUD_TO_DEVICE_DECODER_ELEMENT_NAME);
                            }

                            return(new DecodePayloadResult(externalDecoderResponse)
                            {
                                CloudToDeviceMessage = loRaCloudToDeviceMessage
                            });
                        }
                        catch (JsonReaderException)
                        {
                            // not a json object, use as string
                            return(new DecodePayloadResult(externalRawResponse));
                        }
                    }
                    else
                    {
                        // not a json object, use as string
                        return(new DecodePayloadResult(externalRawResponse));
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Log(devEUI, $"error in decoder handling: {ex.Message}", LogLevel.Error);

                return(new DecodePayloadResult()
                {
                    Error = $"Call to SensorDecoderModule '{sensorDecoderModuleUrl}' failed.",
                    ErrorDetail = ex.Message,
                });
            }
        }