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

Commit 6abdec2

Browse files
author
David R. Williamson
authored
Merge pull request #129 from Azure-Samples/drwill/deviceSamples
Hardcode client version, improve TransportType selection, remove ConfigureAwait, and misc code cleanup
2 parents a31ae00 + 873e825 commit 6abdec2

25 files changed

+543
-308
lines changed

iot-hub/Samples/common/DeviceStreamingCommon.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public static async Task<ClientWebSocket> GetStreamingClientAsync(Uri url, strin
2222
var wsClient = new ClientWebSocket();
2323
wsClient.Options.SetRequestHeader("Authorization", "Bearer " + authorizationToken);
2424

25-
await wsClient.ConnectAsync(url, cancellationToken).ConfigureAwait(false);
25+
await wsClient.ConnectAsync(url, cancellationToken);
2626

2727
return wsClient;
2828
}

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,15 @@ namespace Microsoft.Azure.Devices.Client.Samples
1313
/// </summary>
1414
public class ColorConsoleLogger : ILogger
1515
{
16-
private readonly string _name;
1716
private readonly ColorConsoleLoggerConfiguration _config;
1817

1918
/// <summary>
2019
/// Initializes an instance of <see cref="ColorConsoleLogger"/>.
2120
/// </summary>
2221
/// <param name="name">The category name for each <see cref="ILogger"/> instance. This is usually the class name where the logger is initialized.</param>
2322
/// <param name="config">The <see cref="ColorConsoleLoggerConfiguration"/> settings to be used for logging.</param>
24-
public ColorConsoleLogger(string name, ColorConsoleLoggerConfiguration config)
23+
public ColorConsoleLogger(ColorConsoleLoggerConfiguration config)
2524
{
26-
_name = name;
2725
_config = config;
2826
}
2927

@@ -32,7 +30,6 @@ public ColorConsoleLogger(string name, ColorConsoleLoggerConfiguration config)
3230
/// </summary>
3331
/// <typeparam name="TState">The type of the state to begin scope for.</typeparam>
3432
/// <param name="state">The identifier for the scope.</param>
35-
/// <returns></returns>
3633
public IDisposable BeginScope<TState>(TState state)
3734
{
3835
throw new NotImplementedException();
@@ -42,7 +39,6 @@ public IDisposable BeginScope<TState>(TState state)
4239
/// Checks if the given log level is enabled.
4340
/// </summary>
4441
/// <param name="logLevel">The log level to be checked.</param>
45-
/// <returns></returns>
4642
public bool IsEnabled(LogLevel logLevel)
4743
{
4844
return logLevel >= _config.MinLogLevel;

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

Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -15,49 +15,19 @@ public class ColorConsoleLoggerConfiguration
1515
// If the EventId is set to 0, the logger will log all events.
1616
internal const int DefaultEventId = 0;
1717

18-
private static readonly IReadOnlyDictionary<LogLevel, ConsoleColor> s_defaultColorMapping = new Dictionary<LogLevel, ConsoleColor>
18+
/// <summary>
19+
/// A dictionary containing the log level to console color mappings to be used while writing log entries to the console.
20+
/// </summary>
21+
public IReadOnlyDictionary<LogLevel, ConsoleColor> LogLevelToColorMapping { get; } = new Dictionary<LogLevel, ConsoleColor>
1922
{
2023
{ LogLevel.Trace, ConsoleColor.Blue },
2124
{ LogLevel.Debug, ConsoleColor.DarkYellow },
2225
{ LogLevel.Information, ConsoleColor.Cyan },
2326
{ LogLevel.Warning, ConsoleColor.DarkMagenta },
2427
{ LogLevel.Error, ConsoleColor.Red },
25-
{ LogLevel.Critical, ConsoleColor.DarkRed }
28+
{ LogLevel.Critical, ConsoleColor.DarkRed },
2629
};
2730

28-
/// <summary>
29-
/// Initialize an instance of <see cref="ColorConsoleLoggerConfiguration"/> with default color mappings.
30-
/// </summary>
31-
public ColorConsoleLoggerConfiguration()
32-
{
33-
LogLevelToColorMapping = s_defaultColorMapping;
34-
}
35-
36-
/// <summary>
37-
/// Initialize an instance of <see cref="ColorConsoleLoggerConfiguration"/> by overriding the default color mappings with the supplied custom mappings.
38-
/// </summary>
39-
/// <param name="customConsoleColorMapping">A dictionary of log level to console color mapping that will be used to override the default color mapping.</param>
40-
public ColorConsoleLoggerConfiguration(IDictionary<LogLevel, ConsoleColor> customConsoleColorMapping)
41-
: this ()
42-
{
43-
var map = (IDictionary<LogLevel, ConsoleColor> )LogLevelToColorMapping;
44-
45-
// If a custom color mapping is provided, use it to override the default color mapping.
46-
foreach (KeyValuePair<LogLevel, ConsoleColor> entry in customConsoleColorMapping)
47-
{
48-
if (map.ContainsKey(entry.Key))
49-
{
50-
map[entry.Key] = entry.Value;
51-
}
52-
}
53-
LogLevelToColorMapping = (IReadOnlyDictionary<LogLevel, ConsoleColor>)map;
54-
}
55-
56-
/// <summary>
57-
/// A dictionary containing the log level to console color mappings to be used while writing log entries to the console.
58-
/// </summary>
59-
public IReadOnlyDictionary<LogLevel, ConsoleColor> LogLevelToColorMapping { get; }
60-
6131
/// <summary>
6232
/// The min log level that will be written to the console, defaults to <see cref="LogLevel.Information"/>.
6333
/// </summary>
@@ -66,6 +36,6 @@ public ColorConsoleLoggerConfiguration(IDictionary<LogLevel, ConsoleColor> custo
6636
/// <summary>
6737
/// The list of event Ids to be written to the console. By default, all event Ids are written.
6838
/// </summary>
69-
public IEnumerable<int> EventIds { get; set; } = new List<int>() { DefaultEventId };
39+
public IEnumerable<int> EventIds { get; } = new int[] { DefaultEventId };
7040
}
7141
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public ColorConsoleLoggerProvider(ColorConsoleLoggerConfiguration config)
3030
/// <returns>The created <see cref="ILogger"/> instance.</returns>
3131
public ILogger CreateLogger(string categoryName)
3232
{
33-
return _loggers.GetOrAdd(categoryName, name => new ColorConsoleLogger(name, _config));
33+
return _loggers.GetOrAdd(categoryName, name => new ColorConsoleLogger(_config));
3434
}
3535

3636
/// <summary>

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

Lines changed: 60 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,52 @@ public DeviceReconnectionSample(string deviceConnectionString, TransportType tra
3535
InitializeClient();
3636
}
3737

38+
public async Task RunSampleAsync()
39+
{
40+
using var cts = new CancellationTokenSource();
41+
42+
Console.CancelKeyPress += (sender, eventArgs) =>
43+
{
44+
eventArgs.Cancel = true;
45+
cts.Cancel();
46+
_logger.LogInformation("Sample execution cancellation requested; will exit.");
47+
};
48+
49+
try
50+
{
51+
await Task.WhenAll(SendMessagesAsync(cts.Token), ReceiveMessagesAsync(cts.Token));
52+
}
53+
catch (Exception ex)
54+
{
55+
_logger.LogError($"Unrecoverable exception caught, user action is required, so exiting...: \n{ex}");
56+
}
57+
}
58+
59+
private void InitializeClient()
60+
{
61+
// If the client reports Connected status, it is already in operational state.
62+
if (s_connectionStatus != ConnectionStatus.Connected)
63+
{
64+
lock (_lock)
65+
{
66+
_logger.LogDebug($"Attempting to initialize the client instance, current status={s_connectionStatus}");
67+
68+
// If the device client instance has been previously initialized, then dispose it.
69+
// The s_wasEverConnected variable is required to store if the client ever reported Connected status.
70+
if (s_wasEverConnected && s_connectionStatus == ConnectionStatus.Disconnected)
71+
{
72+
s_deviceClient?.Dispose();
73+
s_wasEverConnected = false;
74+
}
75+
76+
s_deviceClient = DeviceClient.CreateFromConnectionString(_deviceConnectionString, _transportType);
77+
s_deviceClient.SetConnectionStatusChangesHandler(ConnectionStatusChangeHandler);
78+
s_deviceClient.OperationTimeoutInMilliseconds = (uint)s_operationTimeout.TotalMilliseconds;
79+
_logger.LogDebug($"Initialized the client instance.");
80+
}
81+
}
82+
}
83+
3884
private void ConnectionStatusChangeHandler(ConnectionStatus status, ConnectionStatusChangeReason reason)
3985
{
4086
_logger.LogDebug($"Connection status changed: status={status}, reason={reason}");
@@ -98,59 +144,13 @@ private void ConnectionStatusChangeHandler(ConnectionStatus status, ConnectionSt
98144
}
99145
}
100146

101-
public async Task RunSampleAsync()
102-
{
103-
using var cts = new CancellationTokenSource();
104-
105-
Console.CancelKeyPress += (sender, eventArgs) =>
106-
{
107-
eventArgs.Cancel = true;
108-
cts.Cancel();
109-
_logger.LogInformation("Sample execution cancellation requested, will exit.");
110-
};
111-
112-
try
113-
{
114-
await Task.WhenAll(SendMessagesAsync(cts.Token), ReceiveMessagesAsync(cts.Token));
115-
}
116-
catch (Exception ex)
117-
{
118-
_logger.LogError($"Unrecoverable exception caught, user action is required, so exiting...: \n{ex}");
119-
}
120-
}
121-
122-
private void InitializeClient()
123-
{
124-
// If the client reports Connected status, it is already in operational state.
125-
if (s_connectionStatus != ConnectionStatus.Connected)
126-
{
127-
lock (_lock)
128-
{
129-
_logger.LogDebug($"Attempting to initialize the client instance, current status={s_connectionStatus}");
130-
131-
// If the device client instance has been previously initialized, then dispose it.
132-
// The s_wasEverConnected variable is required to store if the client ever reported Connected status.
133-
if (s_wasEverConnected && s_connectionStatus == ConnectionStatus.Disconnected)
134-
{
135-
s_deviceClient?.Dispose();
136-
s_wasEverConnected = false;
137-
}
138-
139-
s_deviceClient = DeviceClient.CreateFromConnectionString(_deviceConnectionString, _transportType);
140-
s_deviceClient.SetConnectionStatusChangesHandler(ConnectionStatusChangeHandler);
141-
s_deviceClient.OperationTimeoutInMilliseconds = (uint)s_operationTimeout.TotalMilliseconds;
142-
_logger.LogDebug($"Initialized the client instance.");
143-
}
144-
}
145-
}
146-
147147
private async Task SendMessagesAsync(CancellationToken cancellationToken)
148148
{
149149
int count = 0;
150+
150151
while (!cancellationToken.IsCancellationRequested)
151152
{
152-
count++;
153-
_logger.LogInformation($"Device sending message {count} to IoTHub...");
153+
_logger.LogInformation($"Device sending message {count++} to IoTHub...");
154154

155155
try
156156
{
@@ -218,24 +218,23 @@ private async Task SendMessageAsync(int count)
218218
private async Task ReceiveMessageAndCompleteAsync()
219219
{
220220
using Message receivedMessage = await s_deviceClient.ReceiveAsync(s_sleepDuration);
221-
if (receivedMessage != null)
221+
if (receivedMessage == null)
222222
{
223-
string messageData = Encoding.ASCII.GetString(receivedMessage.GetBytes());
224-
_logger.LogInformation($"Received message: {messageData}");
223+
_logger.LogInformation("No message received, timed out");
224+
return;
225+
}
225226

226-
int propCount = 0;
227-
foreach (var prop in receivedMessage.Properties)
228-
{
229-
_logger.LogInformation($"Property[{propCount++}> Key={prop.Key} : Value={prop.Value}");
230-
}
227+
string messageData = Encoding.ASCII.GetString(receivedMessage.GetBytes());
228+
var formattedMessage = new StringBuilder($"Received message: {messageData}\n");
231229

232-
await s_deviceClient.CompleteAsync(receivedMessage);
233-
_logger.LogInformation($"Marked message [{messageData}] as \"Complete\".");
234-
}
235-
else
230+
foreach (var prop in receivedMessage.Properties)
236231
{
237-
_logger.LogWarning("No message received, timed out");
232+
formattedMessage.AppendLine($"\tProperty: key={prop.Key}, value={prop.Value}");
238233
}
234+
_logger.LogInformation(formattedMessage.ToString());
235+
236+
await s_deviceClient.CompleteAsync(receivedMessage);
237+
_logger.LogInformation($"Completed message [{messageData}].");
239238
}
240239
}
241240
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
55
<TargetFramework>netcoreapp3.1</TargetFramework>
6+
<LangVersion>8.0</LangVersion>
67
</PropertyGroup>
78

89
<ItemGroup>

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

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ namespace Microsoft.Azure.Devices.Client.Samples
1010
{
1111
public class Program
1212
{
13-
private const string SdkEventProviderPrefix = "Microsoft-Azure-";
14-
1513
// String containing Hostname, Device Id & Device Key in one of the following formats:
1614
// "HostName=<iothub_host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>"
1715
// "HostName=<iothub_host_name>;CredentialType=SharedAccessSignature;DeviceId=<device_id>;SharedAccessSignature=SharedAccessSignature sr=<iot_host>/devices/<device_id>&sig=<token>&se=<expiry_time>";
@@ -22,11 +20,15 @@ public class Program
2220
// - create a launchSettings.json (see launchSettings.json.template) containing the variable
2321
private static string s_deviceConnectionString = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_CONN_STRING");
2422

25-
// Select one of the following transports used by DeviceClient to connect to IoT Hub.
26-
private static TransportType s_transportType = TransportType.Amqp;
27-
//private static TransportType s_transportType = TransportType.Mqtt;
28-
//private static TransportType s_transportType = TransportType.Amqp_WebSocket_Only;
29-
//private static TransportType s_transportType = TransportType.Mqtt_WebSocket_Only;
23+
// Specify one of the following transports used by DeviceClient to connect to IoT Hub.
24+
// Mqtt
25+
// Mqtt_WebSocket_Only
26+
// Mqtt_Tcp_Only
27+
// Amqp
28+
// Amqp_WebSocket_Only
29+
// Amqp_Tcp_only
30+
// Http1
31+
private static readonly string s_transportType = Environment.GetEnvironmentVariable("IOTHUB_DEVICE_TRANSPORT_TYPE");
3032

3133
public static async Task<int> Main(string[] args)
3234
{
@@ -40,18 +42,40 @@ public static async Task<int> Main(string[] args)
4042
MinLogLevel = LogLevel.Debug,
4143
});
4244
var logger = loggerFactory.CreateLogger<Program>();
43-
var sdkEventListener = new ConsoleEventListener(SdkEventProviderPrefix, logger);
45+
46+
const string SdkEventProviderPrefix = "Microsoft-Azure-";
47+
// Instantiating this seems to do all we need for outputing SDK events to our console log
48+
_ = new ConsoleEventListener(SdkEventProviderPrefix, logger);
4449

4550
if (string.IsNullOrEmpty(s_deviceConnectionString) && args.Length > 0)
4651
{
4752
s_deviceConnectionString = args[0];
4853
}
4954

50-
var sample = new DeviceReconnectionSample(s_deviceConnectionString, s_transportType, logger);
55+
var sample = new DeviceReconnectionSample(s_deviceConnectionString, GetTransportType(args), logger);
5156
await sample.RunSampleAsync();
5257

53-
logger.LogInformation("Done, exiting...");
58+
logger.LogInformation("Done.");
5459
return 0;
5560
}
61+
62+
private static TransportType GetTransportType(string[] args)
63+
{
64+
// Check environment variable for transport type
65+
if (Enum.TryParse(s_transportType, true, out TransportType transportType))
66+
{
67+
return transportType;
68+
}
69+
70+
// then check argument for transport type
71+
if (args.Length > 1
72+
&& Enum.TryParse(args[1], true, out transportType))
73+
{
74+
return transportType;
75+
}
76+
77+
// otherwise default to MQTT
78+
return TransportType.Mqtt;
79+
}
5680
}
5781
}

iot-hub/Samples/device/DeviceStreamingSample/DeviceClientStreamingSample.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<PropertyGroup>
44
<OutputType>Exe</OutputType>
55
<TargetFramework>netcoreapp2.0</TargetFramework>
6+
<LangVersion>8.0</LangVersion>
67
</PropertyGroup>
78

89
<ItemGroup>

0 commit comments

Comments
 (0)