IoTHubClientGenerator 1.0.0
See the version list below for details.
dotnet add package IoTHubClientGenerator --version 1.0.0
NuGet\Install-Package IoTHubClientGenerator -Version 1.0.0
<PackageReference Include="IoTHubClientGenerator" Version="1.0.0" />
paket add IoTHubClientGenerator --version 1.0.0
#r "nuget: IoTHubClientGenerator, 1.0.0"
// Install IoTHubClientGenerator as a Cake Addin #addin nuget:?package=IoTHubClientGenerator&version=1.0.0 // Install IoTHubClientGenerator as a Cake Tool #tool nuget:?package=IoTHubClientGenerator&version=1.0.0
IoT Hub Client C# code generator.
To get started, follow this walk-through
This project takes advantage of the new C# 9.0 ability to have a code generation 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 their 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
- AuthenticationMethodAttribute
- C2DMessageAttribute
- ClientOptionsAttribute
- ConnectionStatusAttribute
- DesiredAttribute
- DeviceAttribute
- DirectMethodAttribute
- DpsDeviceAttribute
- DpsSymmetricKeyDeviceAttribute
- DpsTpmDeviceAttribute
- DpsX509CertificateDeviceAttribute
- IoTHubAttribute
- IoTHubDeviceStatusChangesHandlerAttribute
- IoTHubErrorHandlerAttribute
- ReportedAttribute
- TransportSettingAttribute
Enums
Missing features and known issues:
- Move some of the implementations to rely on 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
andContentEncoding
to the send-telemetry method in compile and at runtime - Have the ability to 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
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- IoTHubClientGeneratorSDK (>= 1.0.0)
- Microsoft.Azure.Devices.Client (>= 1.37.2)
- Microsoft.CodeAnalysis.CSharp.Workspaces (>= 3.10.0)
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 | 275 | 9/9/2023 | |
1.1.2 | 223 | 3/22/2023 | |
1.1.0 | 228 | 3/22/2023 | |
1.0.1 | 500 | 6/11/2022 | |
1.0.0 | 501 | 6/11/2022 | |
0.1.9 | 490 | 3/22/2021 | |
0.1.8 | 485 | 1/9/2021 | |
0.1.7 | 517 | 1/6/2021 | |
0.1.6 | 479 | 1/6/2021 | |
0.1.5 | 473 | 12/30/2020 | |
0.1.4 | 515 | 12/28/2020 | |
0.1.3 | 507 | 12/28/2020 | |
0.1.2 | 432 | 12/28/2020 | |
0.1.1 | 475 | 12/28/2020 |