Skip to content

Commit 01e07af

Browse files
LongHaul - Updated setup file and migration guide (#3305)
* LongHaul - Updated setup file and migration guide * cr comments * cr comments * Update Parameters.cs * added doc comments to explain TryGetPayload() behavior * minor * removed getPayloadAsString in methodrequest * test fix
1 parent 585fc30 commit 01e07af

File tree

17 files changed

+169
-42
lines changed

17 files changed

+169
-42
lines changed

SDK v2 migration guide.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ The v2 strategy can be grouped into 3 categories.
101101
- Review the `IsTransient` property to determine if an exception is transient.
102102
- Review the `ErrorCode` property for specific, structured error details.
103103
- For the service client only, the `StatusCode` property is the HTTP status response.
104-
- The exception message is meant for human readable expanation.
104+
- The exception message is meant for human readable explanation.
105105
- Inner exceptions may offer more insight and are worth logging out.
106106
- `TrackingId` is for uniquely identifying specific operations and are useful in sharing with IoT hub support to assist them in more quickly identifying errors that may have been logged by the service.
107107
- `ProvisioningClientException` for provisioning device client and `ProvisioningServiceException` for provisioning service client for exceptions arising from communication attempts with DPS.
@@ -198,6 +198,7 @@ Find a client you currently use below, read the table of API name changes and us
198198
| `Message.CreationTimeUtc` | `TelemetryMessage.CreatedOnUtc`, `IncomingMessage.CreatedOnUtc` | Conforming to the naming guidelines by the Azure SDK team, where DateTime/Offset types have an "On" suffix (and "Utc" suffix when explicitly in UTC).³ |
199199
| `Message.EnqueuedTimeUtc` | `TelemetryMessage.EnqueuedtimeUtc`, `IncomingMessage.EnqueuedTimeUtc` | See³ |
200200
| `Message.ExpiryTimeUtc` | `TelemetryMessage.ExpiresOnUtc`, `IncomingMessage.ExpiresOnUtc` | See³ |
201+
| `Message.GetBytes` | `IncomingMessage.GetPayloadAsBytes` | More descriptive name. |
201202
| `DeviceClient.SetRetryPolicy(...)` | `IotHubClientOptions.RetryPolicy` | Should be specified at initialization time, and putting it in the client options object reduces the client API surface. |
202203
| `ExponentialBackOff` | `IotHubClientExponentialBackOffRetryPolicy` | Clarify it is a retry policy. |
203204
| `MethodRequest` | `DirectMethodRequest` | See⁴ |

e2e/LongHaul/device/IotHub.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ private async void ConnectionStatusChangesHandlerAsync(ConnectionStatusInfo conn
456456

457457
private Task<DirectMethodResponse> DirectMethodCallback(DirectMethodRequest methodRequest)
458458
{
459-
_logger.Trace($"Received direct method [{methodRequest.MethodName}] with payload [{methodRequest.GetPayloadAsJsonString()}].", TraceSeverity.Information);
459+
_logger.Trace($"Received direct method [{methodRequest.MethodName}] with payload [{Encoding.UTF8.GetString(methodRequest.GetPayloadAsBytes())}].", TraceSeverity.Information);
460460

461461
switch (methodRequest.MethodName)
462462
{

e2e/LongHaul/module/IotHub.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System.Collections.Concurrent;
55
using System.Diagnostics;
6+
using System.Text;
67
using Mash.Logging;
78
using Microsoft.Azure.Devices.Client;
89
using static Microsoft.Azure.Devices.LongHaul.Module.LoggingConstants;
@@ -41,11 +42,12 @@ internal sealed class IotHub : IAsyncDisposable
4142
public IotHub(Logger logger, Parameters parameters)
4243
{
4344
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
44-
_moduleConnectionString = parameters.ConnectionString;
45+
_moduleConnectionString = parameters.GatewayHostName == null ? parameters.DeviceModuleConnectionString : parameters.EdgeModuleConnectionString;
4546
_clientOptions = new IotHubClientOptions(parameters.GetTransportSettings())
4647
{
4748
PayloadConvention = parameters.GetPayloadConvention(),
4849
SdkAssignsMessageId = SdkAssignsMessageId.WhenUnset,
50+
GatewayHostName = parameters.GatewayHostName,
4951
};
5052
_moduleClient = null;
5153
}
@@ -357,7 +359,7 @@ private async void ConnectionStatusChangesHandlerAsync(ConnectionStatusInfo conn
357359

358360
private Task<DirectMethodResponse> DirectMethodCallback(DirectMethodRequest methodRequest)
359361
{
360-
_logger.Trace($"Received direct method [{methodRequest.MethodName}] with payload [{methodRequest.GetPayloadAsJsonString()}].", TraceSeverity.Information);
362+
_logger.Trace($"Received direct method [{methodRequest.MethodName}] with payload [{Encoding.UTF8.GetString(methodRequest.GetPayloadAsBytes())}].", TraceSeverity.Information);
361363

362364
switch (methodRequest.MethodName)
363365
{

e2e/LongHaul/module/Parameters.cs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,17 @@ internal class Parameters
2222
{
2323
[Option(
2424
'c',
25-
"ConnectionString",
25+
"DeviceModuleConnectionString",
2626
Required = false,
27-
HelpText = "The connection string for the module to simulate.")]
28-
public string ConnectionString { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_LONG_HAUL_MODULE_CONNECTION_STRING");
27+
HelpText = "The connection string for the Device module to simulate.")]
28+
public string DeviceModuleConnectionString { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_LONG_HAUL_MODULE_CONNECTION_STRING");
29+
30+
[Option(
31+
'e',
32+
"EdgeModuleConnectionString",
33+
Required = false,
34+
HelpText = "The connection string for the Edge module to simulate.")]
35+
public string EdgeModuleConnectionString { get; set; } = Environment.GetEnvironmentVariable("IOTHUB_LONG_HAUL_EDGE_MODULE_CONNECTION_STRING");
2936

3037
[Option(
3138
'i',
@@ -34,6 +41,13 @@ internal class Parameters
3441
HelpText = "The instrumentation key string for application insights.")]
3542
public string InstrumentationKey { get; set; } = Environment.GetEnvironmentVariable("APPLICATION_INSIGHTS_INSTRUMENTATION_KEY");
3643

44+
[Option(
45+
'g',
46+
"GatewayHostName",
47+
Required = false,
48+
HelpText = "The gateway edge device to connect to; if defined, this app will use the EdgeModuleConnectionString, otherwise it uses the DeviceModuleConnectionString.")]
49+
public string GatewayHostName { get; set; }
50+
3751
[Option(
3852
't',
3953
"Transport",

e2e/LongHaul/module/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ await Task
114114

115115
private static Logger InitializeLogging(Parameters parameters)
116116
{
117-
var helper = new IotHubConnectionStringHelper(parameters.ConnectionString);
117+
var helper = new IotHubConnectionStringHelper(parameters.GatewayHostName == null ? parameters.DeviceModuleConnectionString : parameters.EdgeModuleConnectionString);
118118
var logBuilder = new LoggingBuilder
119119
{
120120
AppContext =

e2e/LongHaul/prerequisites/LongHaulSetup.ps1

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,13 @@ $iothubownerSasPrimaryKey = az iot hub policy show --hub-name $iotHubName --name
228228
##################################################################################################################################
229229

230230
$longhaulDeviceId = "LongHaulDevice1"
231-
$longhaulModuleId = "LongHaulModule1"
231+
$longhaulDeviceModuleId = "LongHaulDeviceModule1"
232+
$longhaulEdgeDeviceId = "LongHaulEdgeDevice1"
233+
$longhaulEdgeModuleId = "LongHaulEdgeModule1"
232234
$longhaulDevice = az iot hub device-identity list -g $ResourceGroup --hub-name $iotHubName --query "[?deviceId=='$longhaulDeviceId'].deviceId" --output tsv
233-
$longhaulModule = az iot hub module-identity list -g $ResourceGroup --hub-name $iotHubName --query "[?moduleId=='$longhaulModuleId'].moduleId" --output tsv
235+
$longhaulDeviceModule = az iot hub module-identity list -g $ResourceGroup --hub-name $iotHubName --query "[?moduleId=='$longhaulDeviceModuleId'].moduleId" --output tsv
236+
$longhaulEdgeDevice = az iot hub device-identity list -g $ResourceGroup --hub-name $iotHubName --query "[?deviceId=='$longhaulEdgeDeviceId'].deviceId" --output tsv
237+
$longhaulEdgeModule = az iot hub module-identity list -g $ResourceGroup --hub-name $iotHubName --device-id $longhaulEdgeDeviceId --query "[?moduleId=='$longhaulEdgeModuleId'].moduleId" --output tsv
234238

235239

236240
if (-not $longhaulDevice)
@@ -239,14 +243,27 @@ if (-not $longhaulDevice)
239243
az iot hub device-identity create -g $ResourceGroup --hub-name $iotHubName --device-id $longhaulDeviceId --am shared_private_key
240244
}
241245

242-
if (-not $longhaulModule)
246+
if (-not $longhaulDeviceModule)
243247
{
244-
Write-Host "`nCreating SAK authenticated module $longhaulModuleId on IoT hub."
245-
az iot hub module-identity create -g $ResourceGroup --hub-name $iotHubName --device-id $longhaulDeviceId --module-id $longhaulModuleId --am shared_private_key
248+
Write-Host "`nCreating SAK authenticated module $longhaulDeviceModuleId on IoT hub."
249+
az iot hub module-identity create -g $ResourceGroup --hub-name $iotHubName --device-id $longhaulDeviceId --module-id $longhaulDeviceModuleId --am shared_private_key
250+
}
251+
252+
if (-not $longhaulEdgeDevice)
253+
{
254+
Write-Host "`nCreating SAK authenticated edge device $longhaulEdgeDeviceId on Edge hub."
255+
az iot edge devices create -g $ResourceGroup --hub-name $iotHubName --device id=$longhaulEdgeDeviceId
256+
}
257+
258+
if (-not $longhaulEdgeModule)
259+
{
260+
Write-Host "`nCreating SAK authenticated edge module $longhaulEdgeModuleId on Edge hub."
261+
az iot hub module-identity create -g $ResourceGroup --hub-name $iotHubName --device-id $longhaulEdgeDeviceId --module-id $longhaulEdgeModuleId
246262
}
247263

248264
$longhaulDeviceConnectionString = az iot hub device-identity connection-string show --device-id $longhaulDeviceId --hub-name $iotHubName --resource-group $ResourceGroup --output tsv
249-
$longhaulModuleConnectionString = az iot hub module-identity connection-string show --device-id $longhaulDeviceId --module-id $longhaulModuleId --hub-name $iotHubName --resource-group $ResourceGroup --output tsv
265+
$longhaulDeviceModuleConnectionString = az iot hub module-identity connection-string show --device-id $longhaulDeviceId --module-id $longhaulDeviceModuleId --hub-name $iotHubName --resource-group $ResourceGroup --output tsv
266+
$longhaulEdgeModuleConnectionString = az iot hub module-identity connection-string show --device-id $longhaulEdgeDeviceId --module-id $longhaulEdgeModuleId --hub-name $iotHubName --resource-group $ResourceGroup --output tsv
250267

251268
############################################################################################################################
252269
# Store all secrets in a KeyVault - Values will be pulled down from here to configure environment variables.
@@ -255,7 +272,8 @@ $longhaulModuleConnectionString = az iot hub module-identity connection-string s
255272
$keyvaultKvps = @{
256273
# Environment variables for IoT Hub E2E tests
257274
"IOTHUB-LONG-HAUL-DEVICE-CONNECTION-STRING" = $longhaulDeviceConnectionString;
258-
"IOTHUB-LONG-HAUL-MODULE-CONNECTION-STRING" = $longhaulModuleConnectionString;
275+
"IOTHUB-LONG-HAUL-DEVICE-MODULE-CONNECTION-STRING" = $longhaulDeviceModuleConnectionString;
276+
"IOTHUB-LONG-HAUL-EDGE-MODULE-CONNECTION-STRING" = $longhaulEdgeModuleConnectionString;
259277
"APPLICATION-INSIGHTS-INSTRUMENTATION-KEY" = $instrumentationKey;
260278
"STORAGE-ACCOUNT-CONNECTION-STRING" = $storageAccountConnectionString;
261279
"IOTHUB-CONNECTION-STRING" = $iotHubConnectionString;

iothub/device/samples/getting started/EdgeModuleMethodSample/EdgeModuleMethodSample.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ private void ConnectionStatusChangeHandler(ConnectionStatusInfo connectionInfo)
8686
private Task<DirectMethodResponse> WriteToConsoleAsync(DirectMethodRequest directMethodRequest)
8787
{
8888
Console.WriteLine($"\t *** {directMethodRequest.MethodName} was called.");
89-
Console.WriteLine($"\t{directMethodRequest.GetPayloadAsJsonString()}\n");
89+
Console.WriteLine($"\t{Encoding.UTF8.GetString(directMethodRequest.GetPayloadAsBytes())}\n");
9090

9191
var directMethodResponse = new DirectMethodResponse(200);
9292

iothub/device/samples/getting started/MethodSample/MethodSample.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ private void ConnectionStatusChangeHandler(ConnectionStatusInfo connectionInfo)
8484
private Task<DirectMethodResponse> WriteToConsoleAsync(DirectMethodRequest directMethodRequest)
8585
{
8686
Console.WriteLine($"\t *** {directMethodRequest.MethodName} was called.");
87-
Console.WriteLine($"\t{directMethodRequest.GetPayloadAsJsonString()}\n");
87+
Console.WriteLine($"\t{Encoding.UTF8.GetString(directMethodRequest.GetPayloadAsBytes())}\n");
8888

8989
var directMethodResponse = new DirectMethodResponse(200);
9090

iothub/device/samples/getting started/SimulatedDevice/Program.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// For samples see: https://github.com/Azure/azure-iot-sdk-csharp/tree/main/iothub/device/samples
66

77
using System;
8+
using System.Text;
89
using System.Threading;
910
using System.Threading.Tasks;
1011
using CommandLine;
@@ -63,7 +64,7 @@ private static async Task Main(string[] args)
6364
}
6465
private static Task<DirectMethodResponse> DirectMethodCallback(DirectMethodRequest methodRequest)
6566
{
66-
Console.WriteLine($"Received direct method [{methodRequest.MethodName}] with payload [{methodRequest.GetPayloadAsJsonString()}].");
67+
Console.WriteLine($"Received direct method [{methodRequest.MethodName}] with payload [{Encoding.UTF8.GetString(methodRequest.GetPayloadAsBytes())}].");
6768

6869
switch (methodRequest.MethodName)
6970
{

iothub/device/src/DirectMethod/DirectMethodRequest.cs

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,38 @@ public DirectMethodRequest(string methodName)
111111
/// <summary>
112112
/// The direct method request payload, deserialized to the specified type.
113113
/// </summary>
114+
/// <remarks>
115+
/// Use this method when the payload type is known and it can be deserialized using the configured
116+
/// <see cref="PayloadConvention"/>. If it is not JSON or the type is not known, use <see cref="GetPayloadAsBytes"/>.
117+
/// </remarks>
114118
/// <typeparam name="T">The type to deserialize the direct method request payload to.</typeparam>
115119
/// <param name="payload">When this method returns true, this contains the value of the direct method request payload.
116120
/// When this method returns false, this contains the default value of the type <c>T</c> passed in.</param>
117121
/// <returns><c>true</c> if the direct method request payload can be deserialized to type <c>T</c>; otherwise, <c>false</c>.</returns>
122+
/// <example>
123+
/// <code language="csharp">
124+
/// await client.SetDirectMethodCallbackAsync((directMethodRequest) =>
125+
/// {
126+
/// if (directMethodRequest.TryGetPayload(out MyCustomType customTypePayload))
127+
/// {
128+
/// // do work
129+
/// // ...
130+
///
131+
/// // Acknowlege the direct method call with the status code 200.
132+
/// return Task.FromResult(new DirectMethodResponse(200));
133+
/// }
134+
/// else
135+
/// {
136+
/// // Acknowlege the direct method call the status code 400.
137+
/// return Task.FromResult(new DirectMethodResponse(400));
138+
/// }
139+
///
140+
///
141+
/// // ...
142+
/// },
143+
/// cancellationToken);
144+
/// </code>
145+
/// </example>
118146
public bool TryGetPayload<T>(out T payload)
119147
{
120148
payload = default;
@@ -129,29 +157,36 @@ public bool TryGetPayload<T>(out T payload)
129157
// In case the value cannot be converted using the serializer,
130158
// then return false with the default value of the type <T> passed in.
131159
if (Logging.IsEnabled)
132-
Logging.Error(this, ex, nameof(TryGetPayload));
160+
Logging.Error(this, $"Unable to convert payload to {typeof(T)} due to {ex}", nameof(TryGetPayload));
133161
}
134162

135163
return false;
136164
}
137165

138-
/// <summary>
139-
/// The command payload as a JSON string, if applicable.
140-
/// </summary>
141-
public string GetPayloadAsJsonString()
142-
{
143-
return Payload == null || Payload.Length == 0
144-
? null
145-
: DefaultPayloadConvention.Encoding.GetString(Payload);
146-
}
147-
148166
/// <summary>
149167
/// Get the raw payload bytes.
150168
/// </summary>
169+
/// <remarks>
170+
/// Use this method when the payload is not JSON or the type is not known or the type cannot be deserialized
171+
/// using the configured <see cref="PayloadConvention"/>. Otherwise, use <see cref="TryGetPayload{T}(out T)"/>.
172+
/// </remarks>
151173
/// <returns>A copy of the raw payload as a byte array.</returns>
174+
/// <example>
175+
/// <code language="csharp">
176+
/// await client.SetDirectMethodCallbackAsync((directMethodRequest) =>
177+
/// {
178+
/// byte[] arr = directMethodRequest.GetPayloadAsBytes();
179+
/// // deserialize as needed and do work...
180+
///
181+
/// // Acknowlege the direct method call with the status code 200.
182+
/// return Task.FromResult(new DirectMethodResponse(200));
183+
/// },
184+
/// cancellationToken);
185+
/// </code>
186+
/// </example>
152187
public byte[] GetPayloadAsBytes()
153188
{
154-
return (byte[])Payload.Clone();
189+
return Payload == null || Payload.Length==0 ? null : (byte[])Payload.Clone();
155190
}
156191
}
157192
}

0 commit comments

Comments
 (0)