IoTHubClientGeneratorSDK 1.1.4

dotnet add package IoTHubClientGeneratorSDK --version 1.1.4                
NuGet\Install-Package IoTHubClientGeneratorSDK -Version 1.1.4                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="IoTHubClientGeneratorSDK" Version="1.1.4" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add IoTHubClientGeneratorSDK --version 1.1.4                
#r "nuget: IoTHubClientGeneratorSDK, 1.1.4"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install IoTHubClientGeneratorSDK as a Cake Addin
#addin nuget:?package=IoTHubClientGeneratorSDK&version=1.1.4

// Install IoTHubClientGeneratorSDK as a Cake Tool
#tool nuget:?package=IoTHubClientGeneratorSDK&version=1.1.4                

IoT Hub Client C# code generator SDK package.

This package contains the required Attributes.

To get started, follow this walk-through

This project uses the new C# ability to generate code as part of the C# code compilation process. This code generator can build an IoT Device client program in seconds. For example, the following code creates a device client that can send telemetry, receive commands, update twin reported properties, get desired twin properties updates, get the current connection state, and handle direct method calls:

namespace EasyIoTHubClient
{
    [IoTHub(GeneratedSendMethodName = "SendAsync")]
    partial class IoTDemo
    {
        [Reported("BatteryLevel")] private string _batteryLevel;

        [Desired] private int ReportingFrequencyInHz { get; set; } = 1;

        static async Task Main(string[] args)
        {
            var iotDemo = new IoTDemo();
            await iotDemo.InitIoTHubClientAsync();
            iotDemo.BatteryLevel = "100%";
            await iotDemo.SendDataAsync();
        }

        private async Task SendDataAsync()
        {
            for (int i = 1000; i >= 0; --i)
            {
                BatteryLevel = $"{i % 100}%";
                await SendAsync($"{{\"data\":\"{i}\"", i.ToString(), new CancellationToken());
                await Task.Delay(TimeSpan.FromMilliseconds(1000.0 / ReportingFrequencyInHz));
            }
        }

        [C2DMessage(AutoComplete = true)]
        private void Cloud2DeviceMessage(Message receivedMessage)
        {
            string messageData = Encoding.ASCII.GetString(receivedMessage.GetBytes());
            Console.WriteLine($"Received message: [{messageData}]");
        }

        [DirectMethod]
        private Task<MethodResponse> EchoAsync(MethodRequest request)
        {
            var response = new MethodResponse(request.Data, 200);
            return Task.FromResult(response);
        }


        [ConnectionStatus]
        private (ConnectionStatus Status, ConnectionStatusChangeReason Reason) DeviceConnectionStatus { get; set; }
        
        [IoTHubErrorHandler]
        void IoTHubErrorHandler(string errorMessage, Exception exception)
        {
            Console.WriteLine($"{errorMessage}, Exception: {exception.Message}");
        }
    }
}

Advanced Features

You may use one of the [Device] or the [DPS*] attributes to decorate a DeviceClient property. We can manipulate the IoT Hub device client creation parameters with these attributes and properties. Each property value can be set as a text or can be set as an environment variable value by wrapping the value with the % character, for example:

[Device(ConnectionString="%ConStr%")]
DeviceClient MyClient {get;set;}

Each property value can be set as a variable name or code expression by wrapping the value with the [varName] character, for example:

[Device(ConnectionString="[ConStr]")]
DeviceClient MyClient {get;set;}

The [Device] attribute has a long list of properties and a set of other attributes ([ClientOptions], [TransportSetting], and [AuthenticationMethod]) that create the parameter of the IoT device client Create method. The code generator chooses the correct overload version of the device client Create() function by collecting all these parameters and selecting the suitable function version. The code generator emits an error if there is a missing parameter or a collision between parameters. Example of non-trivial device creation:

    [Device(ConnectionString = "%conString%", DeviceId = "%deviceId%")]
    public DeviceClient DeviceClient { get; set; }

    [TransportSetting]
    public ITransportSettings AmqpTransportSettings { get; } = new AmqpTransportSettings(TransportType.Amqp)
    {
        AmqpConnectionPoolSettings = new AmqpConnectionPoolSettings {MaxPoolSize = 5}, IdleTimeout = TimeSpan.FromMinutes(1)
    };

    [TransportSetting]
    public ITransportSettings MqttTransportSetting { get; } = new MqttTransportSettings(TransportType.Mqtt)
    {
        DefaultReceiveTimeout = TimeSpan.FromMinutes(2)
    };

    [ClientOptions]
    public ClientOptions ClientOptions { get; } = new();

The following code is the result of the example:

private Microsoft.Azure.Devices.Client.DeviceClient CreateDeviceClient()
{
    var theConnectionString = System.Environment.GetEnvironmentVariable("conString");
    var theDeviceId = System.Environment.GetEnvironmentVariable("deviceId");
    ITransportSettings[] transportSettings = new[]{AmqpTransportSettings, MqttTransportSetting};
    var deviceClient = DeviceClient.CreateFromConnectionString(theConnectionString, theDeviceId, transportSettings, ClientOptions);
    return deviceClient;
}

Or, if you want to set the authentication method:

    [Device(Hostname = "%hostName%", TransportType = TransportType.Mqtt)]
    public DeviceClient DeviceClient { get; set; }

    [AuthenticationMethod]
    public IAuthenticationMethod DeviceAuthenticationWithRegistrySymmetricKey { get; } = new DeviceAuthenticationWithRegistrySymmetricKey("deviceId", "key");

And the result generated code is:

private Microsoft.Azure.Devices.Client.DeviceClient CreateDeviceClient()
{
    var theHostname = System.Environment.GetEnvironmentVariable("hostName");
    var theTransportType = TransportType.Mqtt;
    var deviceClient = DeviceClient.Create(theHostname, DeviceAuthenticationWithRegistrySymmetricKey, theTransportType);
    return deviceClient;
}

To use the Device Provisioning Service of Azure IoT, decorate the Device Client property with one of [DpsSymmetricKeyDevice], [DpsTpmDevice], [DpsX509CertificateDevice]

Example:

        [DpsSymmetricKeyDevice(DPSIdScope="scope", DPSTransportType=TransportType.Mqtt, TransportType=TransportType.Mqtt,
            EnrollmentGroupId="%EnrollmentGroupId%", EnrollmentType=DPSEnrollmentType.Group, 
            Id="%RegistrationId%", PrimarySymmetricKey="%SymKey%")]
        public DeviceClient DeviceClient { get; set; }

To compile the code, we need to add the NuGet Packages: Microsoft.Azure.Devices.Provisioning.Client and Microsoft.Azure.Devices.Provisioning.Transport.Mqtt

The resulting generated code:

    private async Task<Microsoft.Azure.Devices.Client.DeviceClient> CreateDeviceClientAsync()
    {
        var theDPSIdScope = "scope";
        var theDPSTransportType = TransportType.Mqtt;
        var theTransportType = TransportType.Mqtt;
        var theEnrollmentGroupId = System.Environment.GetEnvironmentVariable("EnrollmentGroupId");
        var theEnrollmentType = DPSEnrollmentType.Group;
        var theId = System.Environment.GetEnvironmentVariable("RegistrationId");
        var thePrimarySymmetricKey = System.Environment.GetEnvironmentVariable("SymKey");
        using var security = new SecurityProviderSymmetricKey(theId, thePrimarySymmetricKey, null);
        using var transport = new ProvisioningTransportHandlerMqtt();
        var theGlobalDeviceEndpoint = "global.azure-devices-provisioning.net";
        ProvisioningDeviceClient provClient = ProvisioningDeviceClient.Create(theGlobalDeviceEndpoint, theDPSIdScope, security, transport);
        DeviceRegistrationResult result = await provClient.RegisterAsync();
        if (result.Status != ProvisioningRegistrationStatusType.Assigned)
        {
            throw new Exception($"Registration status did not assign a hub, status: {result.Status}");
        }

        IAuthenticationMethod auth = new DeviceAuthenticationWithRegistrySymmetricKey(result.DeviceId, security.GetPrimaryKey());
        var deviceClient = DeviceClient.Create(result.AssignedHub, auth, theTransportType);
        return deviceClient;
    }

IoTHubClientGeneratorSDK Namespace

Classes

Enums

Missing features and known issues:

  • The Source Generator uses the old ISourceGenerator interface and does not benefit from the .NET 6.0 and VS 2022 incremental generator. While it enables using VS2019, the new approach provides much better performance.
  • Move some implementations to the semantic data, not the syntax tree. It will solve several issues, such as spaces around =
  • Have a separate error handler for each attribute instead (or as an override rule) of one global handler
  • Add the ability for the user to provide the MessageSchema ContentType and ContentEncoding to the send-telemetry method in compile and at runtime
  • Can postpone update of reported properties, and only after setting a group of them ask for a batch update of all
  • Add support for:
    • File Uploads
    • Device Modules
    • Device Streams
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.1.4 191 9/9/2023
1.1.2 247 3/22/2023
1.1.0 310 3/22/2023
1.0.1 831 6/11/2022
1.0.0 861 6/11/2022
0.1.9 746 3/22/2021
0.1.8 680 1/9/2021
0.1.7 717 1/6/2021
0.1.6 715 1/6/2021
0.1.5 708 12/30/2020
0.1.4 773 12/28/2020
0.1.3 758 12/28/2020
0.1.2 653 12/28/2020
0.1.1 721 12/28/2020