Skip to content
This repository was archived by the owner on Nov 16, 2023. It is now read-only.

Commit c835f29

Browse files
author
David R. Williamson
authored
Merge pull request #130 from Azure-Samples/drwill/keys
Remove KeysRollover sample; integrate with reconnect sample
2 parents 6abdec2 + 83a25b3 commit c835f29

File tree

7 files changed

+101
-225
lines changed

7 files changed

+101
-225
lines changed

iot-hub/Samples/device/DeviceReconnectionSample/DeviceReconnectionSample.cs

Lines changed: 82 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using Microsoft.Azure.Devices.Client.Exceptions;
55
using Microsoft.Extensions.Logging;
66
using System;
7+
using System.Collections.Generic;
8+
using System.Linq;
79
using System.Text;
810
using System.Threading;
911
using System.Threading.Tasks;
@@ -14,22 +16,35 @@ public class DeviceReconnectionSample
1416
{
1517
private static readonly Random s_randomGenerator = new Random();
1618
private const int TemperatureThreshold = 30;
19+
1720
private static readonly TimeSpan s_sleepDuration = TimeSpan.FromSeconds(5);
1821
private static readonly TimeSpan s_operationTimeout = TimeSpan.FromHours(1);
1922

20-
private readonly string _deviceConnectionString;
23+
private readonly object _initLock = new object();
24+
private readonly List<string> _deviceConnectionStrings;
2125
private readonly TransportType _transportType;
22-
private readonly ILogger _logger;
23-
private readonly object _lock = new object();
2426

27+
private readonly ILogger _logger;
2528
private static DeviceClient s_deviceClient;
29+
2630
private static ConnectionStatus s_connectionStatus;
2731
private static bool s_wasEverConnected;
2832

29-
public DeviceReconnectionSample(string deviceConnectionString, TransportType transportType, ILogger logger)
33+
public DeviceReconnectionSample(List<string> deviceConnectionStrings, TransportType transportType, ILogger logger)
3034
{
3135
_logger = logger;
32-
_deviceConnectionString = deviceConnectionString;
36+
37+
// This class takes a list of potentially valid connection strings (most likely the currently known good primary and secondary keys)
38+
// and will attempt to connect with the first. If it receives feedback that a connection string is invalid, it will discard it, and
39+
// if any more are remaining, will try the next one.
40+
// To test this, either pass an invalid connection string as the first one, or rotate it while the sample is running, and wait about
41+
// 5 minutes.
42+
if (deviceConnectionStrings == null
43+
|| !deviceConnectionStrings.Any())
44+
{
45+
throw new ArgumentException("At least one connection string must be provided.", nameof(deviceConnectionStrings));
46+
}
47+
_deviceConnectionStrings = deviceConnectionStrings;
3348
_transportType = transportType;
3449

3550
InitializeClient();
@@ -59,9 +74,10 @@ public async Task RunSampleAsync()
5974
private void InitializeClient()
6075
{
6176
// If the client reports Connected status, it is already in operational state.
62-
if (s_connectionStatus != ConnectionStatus.Connected)
77+
if (s_connectionStatus != ConnectionStatus.Connected
78+
&& _deviceConnectionStrings.Any())
6379
{
64-
lock (_lock)
80+
lock (_initLock)
6581
{
6682
_logger.LogDebug($"Attempting to initialize the client instance, current status={s_connectionStatus}");
6783

@@ -73,11 +89,21 @@ private void InitializeClient()
7389
s_wasEverConnected = false;
7490
}
7591

76-
s_deviceClient = DeviceClient.CreateFromConnectionString(_deviceConnectionString, _transportType);
92+
s_deviceClient = DeviceClient.CreateFromConnectionString(_deviceConnectionStrings.First(), _transportType);
7793
s_deviceClient.SetConnectionStatusChangesHandler(ConnectionStatusChangeHandler);
7894
s_deviceClient.OperationTimeoutInMilliseconds = (uint)s_operationTimeout.TotalMilliseconds;
95+
}
96+
97+
try
98+
{
99+
// Force connection now
100+
s_deviceClient.OpenAsync().GetAwaiter().GetResult();
79101
_logger.LogDebug($"Initialized the client instance.");
80102
}
103+
catch (UnauthorizedException)
104+
{
105+
// Handled by the ConnectionStatusChangeHandler
106+
}
81107
}
82108
}
83109

@@ -107,8 +133,19 @@ private void ConnectionStatusChangeHandler(ConnectionStatus status, ConnectionSt
107133
switch (reason)
108134
{
109135
case ConnectionStatusChangeReason.Bad_Credential:
110-
_logger.LogWarning("### The supplied credentials were invalid." +
111-
"\nFix the input and then create a new device client instance.");
136+
// When getting this reason, the current connection string being used is not valid.
137+
// If we had a backup, we can try using that.
138+
string badCs = _deviceConnectionStrings[0];
139+
_deviceConnectionStrings.RemoveAt(0);
140+
if (_deviceConnectionStrings.Any())
141+
{
142+
// Not great to print out a connection string, but this is done for sample/demo purposes.
143+
_logger.LogWarning($"The current connection string {badCs} is invalid. Trying another.");
144+
InitializeClient();
145+
break;
146+
}
147+
148+
_logger.LogWarning("### The supplied credentials are invalid. Update the parameters and run again.");
112149
break;
113150

114151
case ConnectionStatusChangeReason.Device_Disabled:
@@ -146,24 +183,27 @@ private void ConnectionStatusChangeHandler(ConnectionStatus status, ConnectionSt
146183

147184
private async Task SendMessagesAsync(CancellationToken cancellationToken)
148185
{
149-
int count = 0;
186+
int messageCount = 0;
150187

151188
while (!cancellationToken.IsCancellationRequested)
152189
{
153-
_logger.LogInformation($"Device sending message {count++} to IoTHub...");
154-
155-
try
156-
{
157-
await SendMessageAsync(count);
158-
}
159-
catch (Exception ex) when (ex is IotHubException exception && exception.IsTransient)
190+
if (s_connectionStatus == ConnectionStatus.Connected)
160191
{
161-
// Inspect the exception to figure out if operation should be retried, or if user-input is required.
162-
_logger.LogError($"An IotHubException was caught, but will try to recover and retry explicitly: {ex}");
163-
}
164-
catch (Exception ex) when (ExceptionHelper.IsNetworkExceptionChain(ex))
165-
{
166-
_logger.LogError($"A network related exception was caught, but will try to recover and retry explicitly: {ex}");
192+
_logger.LogInformation($"Device sending message {++messageCount} to IoT Hub...");
193+
194+
try
195+
{
196+
await SendMessageAsync(messageCount);
197+
}
198+
catch (IotHubException ex) when (ex.IsTransient)
199+
{
200+
// Inspect the exception to figure out if operation should be retried, or if user-input is required.
201+
_logger.LogError($"An IotHubException was caught, but will try to recover and retry explicitly: {ex}");
202+
}
203+
catch (Exception ex) when (ExceptionHelper.IsNetworkExceptionChain(ex))
204+
{
205+
_logger.LogError($"A network related exception was caught, but will try to recover and retry explicitly: {ex}");
206+
}
167207
}
168208

169209
await Task.Delay(s_sleepDuration);
@@ -174,18 +214,24 @@ private async Task ReceiveMessagesAsync(CancellationToken cancellationToken)
174214
{
175215
while (!cancellationToken.IsCancellationRequested)
176216
{
217+
if (s_connectionStatus != ConnectionStatus.Connected)
218+
{
219+
await Task.Delay(s_sleepDuration);
220+
continue;
221+
}
222+
177223
_logger.LogInformation($"Device waiting for C2D messages from the hub - for {s_sleepDuration}...");
178224
_logger.LogInformation("Use the IoT Hub Azure Portal or Azure IoT Explorer to send a message to this device.");
179225

180226
try
181227
{
182228
await ReceiveMessageAndCompleteAsync();
183229
}
184-
catch (Exception ex) when (ex is DeviceMessageLockLostException)
230+
catch (DeviceMessageLockLostException ex)
185231
{
186232
_logger.LogWarning($"Attempted to complete a received message whose lock token has expired; ignoring: {ex}");
187233
}
188-
catch (Exception ex) when (ex is IotHubException exception && exception.IsTransient)
234+
catch (IotHubException ex) when (ex.IsTransient)
189235
{
190236
// Inspect the exception to figure out if operation should be retried, or if user-input is required.
191237
_logger.LogError($"An IotHubException was caught, but will try to recover and retry explicitly: {ex}");
@@ -197,35 +243,35 @@ private async Task ReceiveMessagesAsync(CancellationToken cancellationToken)
197243
}
198244
}
199245

200-
private async Task SendMessageAsync(int count)
246+
private async Task SendMessageAsync(int messageId)
201247
{
202-
var _temperature = s_randomGenerator.Next(20, 35);
203-
var _humidity = s_randomGenerator.Next(60, 80);
204-
string dataBuffer = $"{{\"temperature\":{_temperature},\"humidity\":{_humidity}}}";
248+
var temperature = s_randomGenerator.Next(20, 35);
249+
var humidity = s_randomGenerator.Next(60, 80);
250+
string messagePayload = $"{{\"temperature\":{temperature},\"humidity\":{humidity}}}";
205251

206-
using var eventMessage = new Message(Encoding.UTF8.GetBytes(dataBuffer))
252+
using var eventMessage = new Message(Encoding.UTF8.GetBytes(messagePayload))
207253
{
208-
MessageId = count.ToString(),
254+
MessageId = messageId.ToString(),
209255
ContentEncoding = Encoding.UTF8.ToString(),
210256
ContentType = "application/json",
211257
};
212-
eventMessage.Properties.Add("temperatureAlert", (_temperature > TemperatureThreshold) ? "true" : "false");
258+
eventMessage.Properties.Add("temperatureAlert", (temperature > TemperatureThreshold) ? "true" : "false");
213259

214260
await s_deviceClient.SendEventAsync(eventMessage);
215-
_logger.LogInformation($"Sent message: {count}, Data: [{dataBuffer}]");
261+
_logger.LogInformation($"Sent message {messageId} with data [{messagePayload}]");
216262
}
217263

218264
private async Task ReceiveMessageAndCompleteAsync()
219265
{
220266
using Message receivedMessage = await s_deviceClient.ReceiveAsync(s_sleepDuration);
221267
if (receivedMessage == null)
222268
{
223-
_logger.LogInformation("No message received, timed out");
269+
_logger.LogInformation("No message received; timed out.");
224270
return;
225271
}
226272

227273
string messageData = Encoding.ASCII.GetString(receivedMessage.GetBytes());
228-
var formattedMessage = new StringBuilder($"Received message: {messageData}\n");
274+
var formattedMessage = new StringBuilder($"Received message: [{messageData}]\n");
229275

230276
foreach (var prop in receivedMessage.Properties)
231277
{

iot-hub/Samples/device/DeviceReconnectionSample/Program.cs

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

44
using Microsoft.Extensions.Logging;
55
using System;
6+
using System.Collections.Generic;
67
using System.Diagnostics.Tracing;
78
using System.Threading.Tasks;
89

@@ -18,7 +19,8 @@ public class Program
1819
// - pass this value as a command-prompt argument
1920
// - set the IOTHUB_DEVICE_CONN_STRING environment variable
2021
// - create a launchSettings.json (see launchSettings.json.template) containing the variable
21-
private static string s_deviceConnectionString = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_CONN_STRING");
22+
private static string s_deviceConnectionStringPrimary = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_CONN_STRING");
23+
private static string s_deviceConnectionStringSecondary = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_CONN_STRING_SECONDARY");
2224

2325
// Specify one of the following transports used by DeviceClient to connect to IoT Hub.
2426
// Mqtt
@@ -47,12 +49,23 @@ public static async Task<int> Main(string[] args)
4749
// Instantiating this seems to do all we need for outputing SDK events to our console log
4850
_ = new ConsoleEventListener(SdkEventProviderPrefix, logger);
4951

50-
if (string.IsNullOrEmpty(s_deviceConnectionString) && args.Length > 0)
52+
var connectionStrings = new List<string>(2);
53+
if (string.IsNullOrEmpty(s_deviceConnectionStringPrimary) && args.Length > 0)
5154
{
52-
s_deviceConnectionString = args[0];
55+
s_deviceConnectionStringPrimary = args[0];
5356
}
57+
connectionStrings.Add(s_deviceConnectionStringPrimary);
5458

55-
var sample = new DeviceReconnectionSample(s_deviceConnectionString, GetTransportType(args), logger);
59+
if (string.IsNullOrEmpty(s_deviceConnectionStringSecondary) && args.Length > 1)
60+
{
61+
s_deviceConnectionStringSecondary = args[1];
62+
}
63+
if (!string.IsNullOrWhiteSpace(s_deviceConnectionStringSecondary))
64+
{
65+
connectionStrings.Add(s_deviceConnectionStringSecondary);
66+
}
67+
68+
var sample = new DeviceReconnectionSample(connectionStrings, GetTransportType(args), logger);
5669
await sample.RunSampleAsync();
5770

5871
logger.LogInformation("Done.");
@@ -68,8 +81,8 @@ private static TransportType GetTransportType(string[] args)
6881
}
6982

7083
// then check argument for transport type
71-
if (args.Length > 1
72-
&& Enum.TryParse(args[1], true, out transportType))
84+
if (args.Length > 2
85+
&& Enum.TryParse(args[2], true, out transportType))
7386
{
7487
return transportType;
7588
}

iot-hub/Samples/device/IoTHubDeviceSamples.sln

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ VisualStudioVersion = 16.0.30320.27
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileUploadSample", "FileUploadSample\FileUploadSample.csproj", "{B0E80EC3-9655-44E6-8671-34404879E557}"
77
EndProject
8-
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KeysRolloverSample", "KeysRolloverSample\KeysRolloverSample.csproj", "{06A47F79-1AFE-47D8-8A39-0217449D4007}"
9-
EndProject
108
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MessageSample", "MessageSample\MessageSample.csproj", "{5EF666EB-4C46-47CF-9175-C403DDFB24DD}"
119
EndProject
1210
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MethodSample", "MethodSample\MethodSample.csproj", "{2834C055-7427-4742-BE88-0EC7E0B8FB1D}"
@@ -27,10 +25,6 @@ Global
2725
{B0E80EC3-9655-44E6-8671-34404879E557}.Debug|Any CPU.Build.0 = Debug|Any CPU
2826
{B0E80EC3-9655-44E6-8671-34404879E557}.Release|Any CPU.ActiveCfg = Release|Any CPU
2927
{B0E80EC3-9655-44E6-8671-34404879E557}.Release|Any CPU.Build.0 = Release|Any CPU
30-
{06A47F79-1AFE-47D8-8A39-0217449D4007}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31-
{06A47F79-1AFE-47D8-8A39-0217449D4007}.Debug|Any CPU.Build.0 = Debug|Any CPU
32-
{06A47F79-1AFE-47D8-8A39-0217449D4007}.Release|Any CPU.ActiveCfg = Release|Any CPU
33-
{06A47F79-1AFE-47D8-8A39-0217449D4007}.Release|Any CPU.Build.0 = Release|Any CPU
3428
{5EF666EB-4C46-47CF-9175-C403DDFB24DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
3529
{5EF666EB-4C46-47CF-9175-C403DDFB24DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
3630
{5EF666EB-4C46-47CF-9175-C403DDFB24DD}.Release|Any CPU.ActiveCfg = Release|Any CPU

iot-hub/Samples/device/KeysRolloverSample/KeyRolloverSample.cs

Lines changed: 0 additions & 78 deletions
This file was deleted.

iot-hub/Samples/device/KeysRolloverSample/KeysRolloverSample.csproj

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)