1

Using C#, the Windows Form Template from Visual Studio and the Microsoft Azure Client SDK

I'm trying to send a message to an IOT Hub. I tested connection String with a Virtual Pi and it works there, I can see the connection and incoming messages in the Azure Shell.

Imports:

using System.Windows.Forms;
using Microsoft.Azure.Devices;
using Message = Microsoft.Azure.Devices.Message;
static string connectionString = "HostName=****.azure- devices.net;DeviceId=****;SharedAccessKey=*******=";
static string deviceId = "SensorTest";
static ServiceClient serviceClient;

serviceClient = ServiceClient.CreateFromConnectionString(connectionString);
SendMessageToCloud("takemystringyoupieceof***").Wait();


private static async Task SendMessageToCloud(string s)
        {
            MyData data = new MyData
            {
                Thing1 = "string",
                Thing2 = "string",
                Thing3 = 1234,
                Thing4 = "string",
                Thing5 = s
            };

            var serializeData = JsonConvert.SerializeObject(data);
            var commandMessage = new Message(Encoding.ASCII.GetBytes(serializeData));
            await serviceClient.SendAsync(deviceId, commandMessage);
        }

This throws an Inner Exception:

{"Put token failed. status-code: 401, status-description:
Unauthorized: When KeyName is empty the resource URI must include a device id (Value '****.azure- devices.net').."} 
System.Exception {Microsoft.Azure.Devices.Common.Exceptions.UnauthorizedException}

I would like some help understanding the error message:

  • Isn't KeyName "SharedKey" in this instance?`
  • The deviceID is included as you can see above?
  • The Value in the error message is the value for hostname?

For working code example, myData class:

internal class MyData
    {
        public string Thing1 { get; set; }
        public string Thing2 { get; internal set; }
        public int Thing3 { get; set; }
        public string Thing4 { get; set; }
        public string Thing5 { get; set; }

    }

chris
  • 181
  • 2
  • 18

1 Answers1

2

You are using a DeviceClient connection string with the ServiceClient. The SendAsync you are calling in your SendMessageToCloud is actually a Cloud to Device API. So depending on your intention, the answer is you either need to use the DeviceClient (a helpful sample can be found here) or you want to use an appropriate Service connection string which can be found in the Shared access policies blade for the IoTHub in the portal. Practicing least privilege, the Service key allows cloud-to-device messages (details on shared access policies can be found here)

SeanK
  • 71
  • 1
  • Thanks for the pointer in the right direction, but I'm running into further Issues while following the example you linked. First of all the TransportType does not contain a definition for Mqtt, but the documentation sais otherwise. Second problem is that "DeviceClient" does not work although Microsoft.Azure.Devices is imported. – chris Jun 22 '21 at 17:17
  • 1
    The enum is in Microsoft.Azure.Devices.Client namespace. You generally have to have device side code and service side code to see the messages landing in the iothub coming from devices. I like to use the [Azure IoT Hub VS Code extension](https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.azure-iot-toolkit) to act as the service side code monitoring the built-in endpoint explained [here](https://learn.microsoft.com/en-us/azure/iot-hub/iot-hub-vscode-iot-toolkit-cloud-device-messaging). – SeanK Jun 22 '21 at 22:43
  • Could you provide more details on how the DeviceClient doesn't work? I'm sorry I can't find a good walkthrough or tutorial for .net but there is very clear code for [connecting](https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/master/iot-hub/Samples/device/DeviceReconnectionSample#initialize-the-client) and [sending telemetry](https://github.com/Azure-Samples/azure-iot-samples-csharp/tree/master/iot-hub/Samples/device/DeviceReconnectionSample#send-device-to-cloud-telemetry) in the readme of the sample. – SeanK Jun 22 '21 at 22:43
  • Somehow I had trouble with the import because - as you pointed out - ServiceClient was the wrong choice. This lead to some issues when I then wanted to start using DeviceClient, as I still had code using ServiceClient, but it is solved now, thanks for your help! – chris Jun 23 '21 at 11:41