Azure / azure-iot-sdk-csharp

A C# SDK for connecting devices to Microsoft Azure IoT services
Other
468 stars 492 forks source link

Device client unregistered after calling a direct method with no payload #452

Closed davidjrh closed 4 years ago

davidjrh commented 6 years ago

Description of the issue:

This seems a bug not from the device point of view, since the device registers correctly. I found the problem when building a client application with the Microsoft.Azure.Devices nuget (v1.6.0). After having the device correctly registered and responding to the direct methods calls done through the Azure portal, once I call the direct method of the device from a client app, the device is no longer available (message exception saying my device was not found).

Code sample exhibiting the issue:

I initially created a console app to call a direct method, that works well. The call was something like this:

var connectionString = "HostName=xxxx.azure-devices.net;SharedAccessKeyName=xxxbowner;SharedAccessKey=...";
using (var serviceClient = ServiceClient.CreateFromConnectionString(connectionString))
{
   var methodInvocation = new CloudToDeviceMethod("MyMethodName") { ResponseTimeout = TimeSpan.FromSeconds(30) };
   var response = serviceClient.InvokeDeviceMethodAsync("mydevicename", methodInvocation).Result; 
}

But then I moved the code to another app and was causing the device being unregistered. After trying to find a difference, I found the cause using Fiddler. The console app was sending the following request body:

{
  "methodName": "OpenTheDoor",
  "payload": null,
  "responseTimeoutInSeconds": 30
}

while the second app was sending the following on the request body:

{
  "methodName": "OpenTheDoor",
  "responseTimeoutInSeconds": 30
}

The second application had this setting on the serializer:

JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
            {
                NullValueHandling = NullValueHandling.Ignore
            };

So the problem I see on the IoT API, is that if for whatever reason I don't send the "payload" element on the request body, the device is disconnected, sounds like a bug on the server side.

Another workround is to send an explicit empty payload like this one:

var connectionString = "HostName=xxxx.azure-devices.net;SharedAccessKeyName=xxxbowner;SharedAccessKey=...";
using (var serviceClient = ServiceClient.CreateFromConnectionString(connectionString))
{
   var methodInvocation = new CloudToDeviceMethod("MyMethodName") { ResponseTimeout = TimeSpan.FromSeconds(30) };
   methodInvocation.SetPayloadJson(JsonConvert.SerializeObject(""));
   var response = serviceClient.InvokeDeviceMethodAsync("mydevicename", methodInvocation).Result; 
}
zolvarga commented 6 years ago

@davidjrh

Thanks for reporting the issue we will take a look at it.

Best Regards, Zoltan

timtay-microsoft commented 4 years ago

This may have been a service side bug at some point, but I can't repro this on the current client SDK version against the current service, so I'm closing this issue

az-iot-builder-01 commented 4 years ago

@davidjrh, @timtay-microsoft, thank you for your contribution to our open-sourced project! Please help us improve by filling out this 2-minute customer satisfaction survey