コード例 #1
0
 /// <inheritdoc cref="IMqttClientConfigBuilder.WithAuthentication" />
 public IMqttClientConfigBuilder WithAuthentication(string?method, byte[]?data)
 {
     _builder.WithAuthentication(method, data);
     return(this);
 }
コード例 #2
0
        public async Task ConnectAsync(Options options, TaskCompletionSource <int> closedPromise)
        {
            if (options.Verbose)
            {
                MqttNetGlobalLogger.LogMessagePublished += (s, e) =>
                {
                    var trace = $">> [{e.LogMessage.Timestamp:O}] [{e.LogMessage.ThreadId}] [{e.LogMessage.Source}] [{e.LogMessage.Level}]: {e.LogMessage.Message}";
                    if (e.LogMessage.Exception != null)
                    {
                        trace += Environment.NewLine + e.LogMessage.Exception.ToString();
                    }

                    Console.WriteLine(trace);
                };
            }

            var factory = new MqttFactory();
            var client  = factory.CreateMqttClient();

            client.UseApplicationMessageReceivedHandler(msg => this.HandleMessageAsync(msg));

            var tlsOptions = new MqttClientOptionsBuilderTlsParameters();

            tlsOptions.UseTls = true;

            var clientOptions = new MqttClientOptionsBuilder()
                                .WithTcpServer(opt => opt.NoDelay = true)
                                .WithClientId(options.ClientId)
                                .WithTcpServer(options.Hostname, 8883)
                                .WithTls(tlsOptions)
                                .WithProtocolVersion(MQTTnet.Formatter.MqttProtocolVersion.V500)
                                // .WithUserProperty("host", hostName) // normally it is not needed as SNI is added by most TLS implementations.
                                .WithUserProperty("api-version", "2020-10-01-preview")
                                .WithCommunicationTimeout(TimeSpan.FromSeconds(30))
                                .WithKeepAlivePeriod(TimeSpan.FromSeconds(300))
                                .WithCleanSession(false); // keep existing subscriptions

            if (string.IsNullOrEmpty(options.SasKey))
            {
                tlsOptions.Certificates = new[] { new X509Certificate(options.ClientCertificatePath, options.ClientCertificatePassword) };
                clientOptions.WithAuthentication("X509", null);
            }
            else
            {
                var    at           = DateTimeOffset.UtcNow;
                var    atString     = at.ToUnixTimeMilliseconds().ToString();
                var    expiry       = at.AddMinutes(40);
                var    expiryString = expiry.ToUnixTimeMilliseconds().ToString();
                string toSign       = $"{options.Hostname}\n{options.ClientId}\n{options.SasPolicy}\n{atString}\n{expiryString}\n";
                var    hmac         = new HMACSHA256(Convert.FromBase64String(options.SasKey));
                var    sas          = hmac.ComputeHash(Encoding.UTF8.GetBytes(toSign));

                clientOptions
                .WithAuthentication("SAS", sas)
                .WithUserProperty("sas-at", atString)
                .WithUserProperty("sas-expiry", expiryString);
                if (!string.IsNullOrEmpty(options.SasPolicy))
                {
                    // include only if using SAS policy
                    clientOptions.WithUserProperty("sas-policy", options.SasPolicy);
                }
            }

            // Set up disconnection handling: print out details and allow process to close
            client.UseDisconnectedHandler(disconnectArgs =>
            {
                Console.WriteLine($"Disconnected: {disconnectArgs.ReasonCode}");
                if (disconnectArgs.AuthenticateResult?.UserProperties != null)
                {
                    foreach (var prop in disconnectArgs.AuthenticateResult.UserProperties)
                    {
                        Console.WriteLine($"{prop.Name}: {prop.Value}");
                    }
                }
                closedPromise.SetResult(1);
            });

            try
            {
                // once connection is established, we may start receiving messages based on subscriptions
                // from previous connections - better set client before connection.
                this.client = client;

                var connectResult = await client.ConnectAsync(clientOptions.Build(), CancellationToken.None);

                if (connectResult.ResultCode != MqttClientConnectResultCode.Success)
                {
                    var status = GetStatus(connectResult.UserProperties)?.ToString("x4");
                    throw new Exception($"Connect failed. Status: {connectResult.ResultCode}; status: {status}");
                }

                if (!connectResult.IsSessionPresent)
                {
                    // only subscribe if haven't subscribed already.
                    // This optimization only works of a single SUBSCRIBE is used to subscribe to everything at once or
                    // if app keeps track of what has been successfully acknowledged by server.
                    var subscribeResult = await client.SubscribeAsync(
                        new MqttTopicFilter
                    {
                        Topic = "$iothub/methods/+",
                        QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce
                    },
                        new MqttTopicFilter
                    {
                        Topic = "$iothub/commands",
                        QualityOfServiceLevel = MqttQualityOfServiceLevel.AtLeastOnce
                    },
                        new MqttTopicFilter
                    {
                        Topic = "$iothub/twin/patch/desired",
                        QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce
                    });

                    // make sure subscriptions were successful
                    if (subscribeResult.Items.Count != 3 ||
                        subscribeResult.Items[0].ResultCode != MqttClientSubscribeResultCode.GrantedQoS0 ||
                        subscribeResult.Items[1].ResultCode != MqttClientSubscribeResultCode.GrantedQoS1 ||
                        subscribeResult.Items[2].ResultCode != MqttClientSubscribeResultCode.GrantedQoS0)
                    {
                        throw new ApplicationException("Failed to subscribe");
                    }
                }
            }
            catch (MqttConnectingFailedException ex)
            {
                Console.WriteLine($"Failed to connect, reason code: {ex.ResultCode}");
                if (ex.Result?.UserProperties != null)
                {
                    foreach (var prop in ex.Result.UserProperties)
                    {
                        Console.WriteLine($"{prop.Name}: {prop.Value}");
                    }
                }
                throw;
            }
        }