MQTTnet

MQTTnet 4.X 版本

 

MqttService 

public class MqttService : IHostedService, IDisposable
{
    private readonly IManagedMqttClient _mqttClient;
    private readonly ILogger<MqttService> _logger;
    private readonly AppSettings _options;

    public DateTime? LastConnectedTime { get; private set; }
    public DateTime? LastDisconnectedTime { get; private set; }
    public int DisconnectCount { get; private set; }
    int retryCount = 3;

    private readonly ConcurrentDictionary<string, Action<string>> _messageHandlers = new();

    // 事件:当收到消息时触发,供 SignalR 或其他服务消费
    public event Func<string, string, Task>? MessageReceived;

    // 2. 构造函数只负责赋值和事件绑定,不执行连接操作
    public MqttService(
        IManagedMqttClient mqttClient,
        ILogger<MqttService> logger,
        IOptions<AppSettings> options)
    {
        _mqttClient = mqttClient ?? throw new ArgumentNullException(nameof(mqttClient));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        _options = options.Value ?? throw new ArgumentException(nameof(options));
        //// 如果需要监听变化
        //_options.OnChange(settings =>
        //{
        //    // 处理配置变化
        //    Console.WriteLine("Config changed!");
        //});

        // 3. 绑定事件处理程序 
        _mqttClient.ConnectedAsync += e =>
        {
            _logger.LogInformation("MQTT 4.x 已成功连接并建立心跳");
            return Task.CompletedTask;
        };

        
        _mqttClient.DisconnectedAsync += e =>
        {
            _logger.LogWarning($"MQTT 断开连接,原因: {e.Reason},异常: {e.Exception?.Message}");
            LastDisconnectedTime = DateTime.UtcNow;
            DisconnectCount++;
            _logger.LogWarning($"第{DisconnectCount}次断开,原因: {e.Reason}");

            // 根据断开原因采取不同策略
            if (e.Reason == MqttClientDisconnectReason.NormalDisconnection)
            {
                _logger.LogInformation("正常断开,等待5秒后重连...");
                //await Task.Delay(5000);
            }
            else
            {
                // 异常断开,使用指数退避策略
                int delay = Math.Min(30000, 1000 * (int)Math.Pow(2, retryCount));
                _logger.LogInformation($"异常断开,{delay / 1000}秒后重连...");
                //await Task.Delay(delay);
            }
            return Task.CompletedTask;
        };

        _mqttClient.ApplicationMessageReceivedAsync += e =>
        {
            try
            {
                // 安全检查:防止 ApplicationMessage 为 null
                if (e?.ApplicationMessage == null)
                {
                    _logger.LogWarning("收到空的 MQTT 消息事件。");
                    return Task.CompletedTask;
                }

                // 使用结构化日志替代字符串插值,提升性能并支持日志查询
                // 注意:ConvertPayloadToString 可能涉及编码转换,确保其不会抛出异常
                string payload = e.ApplicationMessage.ConvertPayloadToString() ?? string.Empty;

                _logger.LogInformation($"收到消息 - Topic: {e.ApplicationMessage.Topic}, Payload: {payload}");

                // 在这里可以添加业务逻辑,例如发布内部事件
                // 如果有异步操作,请使用 await
                return Task.CompletedTask;
            }
            catch (Exception ex)
            {
                // 记录异常,防止未处理异常导致 MQTT 客户端断开或应用崩溃
                _logger.LogError(ex, "处理 MQTT 消息时发生错误。");
                return Task.CompletedTask;
            }
        };

        //// 启动托管客户端
        //Task.Run(async () => { await StartAsync(CancellationToken.None); });
        
    }

    private Task _mqttClient_DisconnectedAsync(MQTTnet.Client.MqttClientDisconnectedEventArgs arg)
    {
        throw new NotImplementedException();
    }

    //protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    //{
    //    var config = _options.Mqtt;

    //    if (string.IsNullOrEmpty(config.ServerUrl))
    //    {
    //        _logger.LogError("MQTT ServerUrl is not configured in AppSettings.");
    //        return;
    //    }
    //    // 1. 配置连接选项
    //    var options = new ManagedMqttClientOptionsBuilder()
    //        .WithAutoReconnectDelay(TimeSpan.FromSeconds(5))
    //        .WithClientOptions(new MqttClientOptionsBuilder()
    //            .WithClientId(config.ClientId)
    //            .WithTcpServer(config.ServerUrl)
    //            .WithCredentials(config.Username, config.Password)
    //            .WithCleanSession(false) // 改为false以保持会话状态ithCleanSession()
    //            .WithKeepAlivePeriod(TimeSpan.FromSeconds(30)) // 心跳保活
    //            .Build())
    //        .Build();

    //    // 2. 启动客户端(建立连接)
    //    await _mqttClient.StartAsync(options);

    //    // 3. 订阅主题
    //    await _mqttClient.SubscribeAsync("scada/#");

    //    // 4. 保持服务运行,直到应用停止
    //    await Task.Delay(Timeout.Infinite, stoppingToken);
    //}
    // 4. IHostedService.StartAsync: 应用启动时自动调用
    public async Task StartAsync(CancellationToken cancellationToken)
    {
        if (_mqttClient.IsStarted)
        {
            _logger.LogInformation("MQTT Client is already started.");
            return;
        }

        var config = _options.Mqtt;

        if (string.IsNullOrEmpty(config.ServerUrl))
        {
            _logger.LogError("MQTT ServerUrl is not configured in AppSettings.");
            return;
        }
        //NormalDisconnection 表示连接被正常关闭,但客户端配置了自动重连
        //确保 config.ClientId 在您的配置中是唯一的,如果多个客户端使用相同的ClientId连接同一服务器,后连接的客户端会踢掉先连接的
        //增加待处理消息队列大小, 队列满时策略
        // 强制使用 InterNetwork (IPv4)WithTcpServer(new MqttClientTcpOptions{AddressFamily = System.Net.Sockets.AddressFamily.InterNetwork})
        // 构建 Managed Client 选项
        var options = new ManagedMqttClientOptionsBuilder()
            .WithAutoReconnectDelay(TimeSpan.FromSeconds(5)) // 断线重连延迟
            .WithClientOptions(new MqttClientOptionsBuilder()
            //.WithMaxPendingMessages(1000) // 增加待处理消息队列大小
            //.WithPendingMessagesOverflowStrategy(PendingMessagesOverflowStrategy.DropOldest) // 队列满时策略
                .WithClientId(config.ClientId) 
                .WithTcpServer(config.ServerUrl) // 确保这里只传域名和端口,不带协议头,‌不要‌包含 mqtt:// 前缀。
                .WithCredentials(config.Username, config.Password)
                .WithCleanSession(false) // 改为false以保持会话状态ithCleanSession()
                .WithKeepAlivePeriod(TimeSpan.FromSeconds(30)) // 心跳保活
                .Build())
            .Build();

        try
        {
            _logger.LogInformation("Starting MQTT Client...");
            await _mqttClient.StartAsync(options);
            _logger.LogInformation("MQTT Client Start command issued.");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to start MQTT Client.");
        }
    }

    // 5. IHostedService.StopAsync: 应用停止时自动调用
    public async Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Stopping MQTT Client...");
        if (_mqttClient.IsStarted)
        {
            await _mqttClient.StopAsync();
        }
        _logger.LogInformation("MQTT Client stopped.");
    }

    // 6. 业务方法:发布消息
    public async Task PublishAsync(string topicSuffix, string payload, MqttQualityOfServiceLevel qos = MqttQualityOfServiceLevel.AtMostOnce)
    {
        if (!_mqttClient.IsConnected)
        {
            _logger.LogWarning("MQTT client is not connected. Message will be queued if possible.");
        }

        var config = _options.Mqtt;
        var topic = $"{config.BaseTopic}/{topicSuffix}";

        var message = new MqttApplicationMessageBuilder()
            .WithTopic(topic)
            .WithPayload(payload)
            .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce)
            .Build();

        try
        {
            // EnqueueAsync 是 ManagedClient 的核心优势:断网时缓存,联网后自动发送
            await _mqttClient.EnqueueAsync(message);
            _logger.LogDebug("Enqueued message to {Topic}", topic);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to enqueue message to {Topic}", topic);
        }
    }

    // 7. 业务方法:订阅主题
    public async Task SubscribeAsync(string topicSuffix, MqttQualityOfServiceLevel qos = MqttQualityOfServiceLevel.AtMostOnce)
    {
        if (!_mqttClient.IsStarted)
        {
            _logger.LogInformation("MQTT Client is not already started.");
        }
        var config = _options.Mqtt;
        //var topic = $"{config.BaseTopic}/{topicSuffix}";
        var topic = new MqttTopicFilterBuilder().WithTopic(topicSuffix).WithQualityOfServiceLevel(qos).Build();
        try
        {
            await _mqttClient.SubscribeAsync(new[] { topic });
            _logger.LogInformation("Subscribed to {Topic}", topic);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to subscribe to {Topic}", topic);
        }
    }

    // 8. 重新加载配置后重启客户端(可选)
    public async Task RestartClientAsync()
    {
        _logger.LogInformation("Restarting MQTT Client...");
        await StopAsync(CancellationToken.None);
        await StartAsync(CancellationToken.None);
    }

    public void Dispose()
    {
        _mqttClient?.Dispose();
    }

    // 添加网络连通性检查
    public async Task<bool> CheckServerReachable()
    {
        try
        {
            using var tcpClient = new TcpClient();
            var uri = new Uri(_options.Mqtt.ServerUrl);
            await tcpClient.ConnectAsync(uri.Host, uri.Port > 0 ? uri.Port : 1883);
            return tcpClient.Connected;
        }
        catch
        {
            return false;
        }
    }

    private Task OnConnectedAsync(MqttClientConnectedEventArgs arg)
    {
        _logger.LogInformation("✅ MQTT Connected to broker");
        // 重连后自动恢复订阅(示例)
        return SubscribeAsync("devices/+/telemetry");
    }

    private Task OnDisconnectedAsync(MqttClientDisconnectedEventArgs arg)
    {
        _logger.LogWarning("❌ MQTT Disconnected: {Reason}", arg.Reason);
        return Task.CompletedTask;
    }

    private async Task OnMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg)
    {
        var topic = arg.ApplicationMessage.Topic;
        var payload = Encoding.UTF8.GetString(arg.ApplicationMessage.PayloadSegment);

        _logger.LogDebug("Received [{Topic}]: {Payload}", topic, payload);

        // 触发事件供外部消费
        if (MessageReceived != null)
            await MessageReceived.Invoke(topic, payload);
    }

    //public override async Task StopAsync(CancellationToken cancellationToken)
    //{
    //    if (_mqttClient.IsConnected)
    //        await _mqttClient.DisconnectAsync(cancellationToken: cancellationToken);
    //    _mqttClient.Dispose();
    //    await base.StopAsync(cancellationToken);
    //}

    //protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    //{
    //    while (!stoppingToken.IsCancellationRequested)
    //    {
    //        try
    //        {
    //            if (!_mqttClient.IsConnected)
    //            {
    //                await _mqttClient.ConnectAsync(_options, stoppingToken);
    //            }
    //            await Task.Delay(5000, stoppingToken); // 健康检查间隔
    //        }
    //        catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
    //        {
    //            break;
    //        }
    //        catch (Exception ex)
    //        {
    //            _logger.LogError(ex, "MQTT connection loop error");
    //            await Task.Delay(5000, stoppingToken);
    //        }
    //    }
    //}

}
View Code

ConfigService 

public class ConfigService : IConfigService
{
    private readonly AppSettings _options;
    private readonly IConfiguration _configuration;
    // 注入 IOptionsSnapshot 确保每次请求都能读取到最新的配置文件值
    public ConfigService(IOptionsSnapshot<AppSettings> options, IConfiguration configuration)
    {
        _options = options.Value;
        _configuration = configuration;
    }
    public AppSettings GetAppSettings() => _options;
    public string? GetSingleValue(string key) => _configuration[key];
}
View Code

 

Program.cs

// A. 注册 MqttFactory 为单例 (工厂模式)
builder.Services.AddSingleton<MqttFactory>();

// B. 注册 IManagedMqttClient 为单例
// 使用工厂创建客户端,确保整个应用生命周期中只有一个 MQTT 连接实例
builder.Services.AddSingleton<IManagedMqttClient>(sp =>
{
    var factory = sp.GetRequiredService<MqttFactory>();
    return factory.CreateManagedMqttClient();
});

// C. 注册后台服务 MqttService 为 Hosted Service(负责启动/停止连接)
// AddHostedService 会自动在应用启动时调用 StartAsync,停止时调用 StopAsync
builder.Services.AddHostedService<MqttService>();

//// D. (可选) 如果 Controller 需要注入 IMqttService 接口
//// 将接口映射到具体的 MqttService 实例, 注册其他使用 MQTT 的服务(如 Controller 依赖的服务),
///IManagedMqttClient 为单例,使用工厂创建客户端代替
//builder.Services.AddSingleton<IMqttService>(sp => sp.GetRequiredService<MqttService>());
// ==========================================
View Code
// 1. 注册配置选项
builder.Services.Configure<AppSettings>(builder.Configuration.GetSection("AppSettings"));

AppSettings
    public class AppSettings
    {
        public MqttConfig Mqtt { get; set; } = new();
    }

     public class MqttConfig
    {
        public string ServerUrl { get; set; } = "";
        public string ClientId { get; set; } = "";
        public string Username { get; set; } = "";
        public string Password { get; set; } = "";
        public string BaseTopic { get; set; } = "";
    }
View Code

 

SystemController 

[Route("api/[controller]")]
[ApiController]
public class SystemController : ControllerBase
{
    //private readonly IMqttService _mqttService;
    private readonly IConfigService _configService;
    private readonly ILogger<SystemController> _logger;
    private readonly IManagedMqttClient _mqttClient;

    //public SystemController(IMqttService mqttService, IConfigService configService, ILogger<SystemController> logger)
    //{
    //    _mqttService = mqttService;
    //    _configService = configService;
    //    _logger = logger;
    //}
    public SystemController(IManagedMqttClient mqttClient, IConfigService configService, ILogger<SystemController> logger)
    {
        _mqttClient = mqttClient;
        _configService = configService;
        _logger = logger;
    }

    [HttpPost("start-mqtt")]
    public IActionResult StartMqtt([FromQuery] string topic)
    {
        if (!_mqttClient.IsConnected)
        {
            return BadRequest("MQTT Client is not connected.");
        }
        _mqttClient.SubscribeAsync(topic);
        return Ok(new ApiResponseDto { Success = true, Message = $"已成功订阅 Topic: {topic}" });
    }

    [HttpGet("config")]
    public IActionResult GetConfig([FromQuery] string? key = null)
    {
        if (string.IsNullOrWhiteSpace(key))
        {
            // 返回所有嵌套配置
            return Ok(new ApiResponseDto { Success = true, Data = _configService.GetAppSettings() });
        }
        // 返回单个节点值
        return Ok(new ApiResponseDto { Success = true, Data = _configService.GetSingleValue(key) });
    }
}
View Code

 =======

5.X版本有点问题

#region 手动自动重连和断线重连 
/// <summary>
/// MQTT 后台服务,自动连接、重连、心跳,并可通过 API 手动启停或发布消息。
/// </summary>
public class MqttClientService : BackgroundService, IMqttClientService
{
    private readonly ILogger<MqttClientService> _logger;
    private readonly IOptionsMonitor<MqttSettings> _settings;
    private IMqttClient? _mqttClient;
    private MqttClientOptions? _clientOptions;
    private volatile bool _connected;
    private readonly SemaphoreSlim _connectLock = new(1, 1);

    // 用于手动控制的标志(Start/Stop API)
    private volatile bool _manualStop;
    private readonly TaskCompletionSource _readyTcs = new();

    public bool IsConnected => _connected;
    public event Func<MqttApplicationMessageReceivedEventArgs, Task>? MessageReceived;

    public MqttClientService(ILogger<MqttClientService> logger, IOptionsMonitor<MqttSettings> settings)
    {
        _logger = logger;
        _settings = settings;
    }

    /// <summary>
    /// BackgroundService 主循环,持续维护连接直到应用程序关闭。
    /// </summary>
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // 等待手动 Start(如果外部 API 调用 StartAsync 再开始连接,也可直接开始)
        // 此处设计为自动开始,若需手动启动可注释下面一行,并在 StartAsync 中设置信号。
        _readyTcs.TrySetResult();

        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                // 如果手动停止或退出令牌触发,则断开并等待
                if (_manualStop || stoppingToken.IsCancellationRequested)
                {
                    await DisconnectAsync();
                    await Task.Delay(1000, stoppingToken);
                    continue;
                }

                if (_connected)
                {
                    // 已连接,仅等待断开信号
                    await Task.Delay(1000, stoppingToken);
                    continue;
                }

                // 未连接则尝试连接
                await ConnectAsync(stoppingToken);
            }
            catch (OperationCanceledException opc) when (stoppingToken.IsCancellationRequested)
            {
                // 正常关闭
                _logger.LogInformation($"MqttClientService normal stopped.正常关闭。{opc.Message}");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "MQTT 服务执行异常,将在 5 秒后重试");
                await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
            }
        }
    }

    /// <summary>
    /// 建立 MQTT 连接,使用最新的配置。
    /// </summary>
    private async Task ConnectAsync(CancellationToken cancellationToken)
    {
        await _connectLock.WaitAsync(cancellationToken);
        try
        {
            if (_connected || _mqttClient?.IsConnected == true)
                return;

            var config = _settings.CurrentValue;
            _clientOptions = new MqttClientOptionsBuilder()
                .WithTcpServer(config.Broker, config.Port)
                .WithClientId(config.ClientId)
                .WithCredentials(config.Username, config.Password)
                .WithKeepAlivePeriod(TimeSpan.FromSeconds(config.KeepAlivePeriod))
                .Build();

            var factory = new MqttClientFactory();
            _mqttClient = factory.CreateMqttClient();
            _mqttClient.ConnectedAsync += OnConnected;
            _mqttClient.DisconnectedAsync += OnDisconnected;
            _mqttClient.ApplicationMessageReceivedAsync += OnMessageReceived;

            _logger.LogInformation("正在连接到 MQTT Broker: {Broker}:{Port} ...", config.Broker, config.Port);
            await _mqttClient.ConnectAsync(_clientOptions, cancellationToken);
            _connected = true;
            _logger.LogInformation("MQTT 连接成功");
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "MQTT 连接失败,{Delay}秒后重试", _settings.CurrentValue.ReconnectDelaySeconds);
            CleanupClient();
            await Task.Delay(TimeSpan.FromSeconds(_settings.CurrentValue.ReconnectDelaySeconds), cancellationToken);
        }
        finally
        {
            _connectLock.Release();
        }
    }

    /// <summary>
    /// 断开连接并清理客户端资源。
    /// </summary>
    private async Task DisconnectAsync()
    {
        if (_mqttClient == null) return;

        try
        {
            if (_mqttClient.IsConnected)
            {
                await _mqttClient.DisconnectAsync(MqttClientDisconnectOptionsReason.NormalDisconnection);
            }
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "MQTT 断开时异常");
        }
        finally
        {
            CleanupClient();
            _connected = false;
        }
    }

    private void CleanupClient()
    {
        if (_mqttClient == null) return;
        _mqttClient.ConnectedAsync -= OnConnected;
        _mqttClient.DisconnectedAsync -= OnDisconnected;
        _mqttClient.ApplicationMessageReceivedAsync -= OnMessageReceived;
        _mqttClient.Dispose();
        _mqttClient = null;
    }

    private async Task OnConnected(MqttClientConnectedEventArgs args)
    {
        _connected = true;
        _logger.LogInformation("MQTT 连接事件触发");
        // 连接成功后订阅默认主题
        if (_mqttClient != null)
        {
            var topic = $"{_settings.CurrentValue.TopicPrefix}#";
            await _mqttClient.SubscribeAsync(topic);
            _logger.LogInformation("已订阅主题: {Topic}", topic);
        }
    }

    private async Task OnDisconnected(MqttClientDisconnectedEventArgs args)
    {
        _connected = false;
        _logger.LogWarning("MQTT 断开连接,原因:{Reason}", args.Reason);
        // 自动重连由 ExecuteAsync 主循环处理,此处仅标记状态
    }

    private async Task OnMessageReceived(MqttApplicationMessageReceivedEventArgs args)
    {
        var payload = Encoding.UTF8.GetString(args.ApplicationMessage.Payload);
        _logger.LogInformation("收到消息 [{Topic}]: {Payload}", args.ApplicationMessage.Topic, payload);

        if (MessageReceived != null)
            await MessageReceived.Invoke(args);
    }

    /// <summary>
    /// 手动启动 MQTT 服务(若在 ExecuteAsync 中设置了等待信号,可释放信号启动连接循环)
    /// </summary>
    public async Task StartAsync()
    {
        _manualStop = false;
        _readyTcs.TrySetResult();
        _logger.LogInformation("MQTT 服务手动启动");
        // 触发立即连接尝试
        if (!_connected)
        {
            _ = ConnectAsync(CancellationToken.None);
        }
        await Task.CompletedTask;
    }

    /// <summary>
    /// 手动停止 MQTT 服务(断开连接,后台循环将不再自动重连)
    /// </summary>
    public async Task StopAsync()
    {
        _manualStop = true;
        await DisconnectAsync();
        _logger.LogInformation("MQTT 服务手动停止");
    }

    /// <summary>
    /// 发布消息到指定主题
    /// </summary>
    public async Task PublishAsync(string topic, string payload, bool retain = false, MqttQualityOfServiceLevel qos = MqttQualityOfServiceLevel.AtLeastOnce)
    {
        if (!_connected || _mqttClient == null)
            throw new InvalidOperationException("MQTT 未连接");

        var message = new MqttApplicationMessageBuilder()
            .WithTopic(topic)
            .WithPayload(payload)
            .WithQualityOfServiceLevel(qos)
            .WithRetainFlag(retain)
            .Build();

        await _mqttClient.PublishAsync(message);
        _logger.LogInformation("已发布到 [{Topic}]: {Payload}", topic, payload);
    }

    /// <summary>
    /// 订阅指定主题(需已连接)
    /// </summary>
    public async Task SubscribeAsync(string topic, MqttQualityOfServiceLevel qos = MqttQualityOfServiceLevel.AtLeastOnce)
    {
        if (!_connected || _mqttClient == null)
            throw new InvalidOperationException("MQTT 未连接,无法订阅主题");

        var options = new MqttClientSubscribeOptionsBuilder()
            .WithTopicFilter(topic, qos)
            .Build();

        await _mqttClient.SubscribeAsync(options);
        _logger.LogInformation("已订阅主题: {Topic} (QoS: {Qos})", topic, qos);
    }


    public override async Task StopAsync(CancellationToken cancellationToken)
    {
        _manualStop = true;
        await DisconnectAsync();
        await base.StopAsync(cancellationToken);
    }

    public override void Dispose()
    {
        _mqttClient?.Dispose();
        _connectLock.Dispose();
        base.Dispose();
    }

}
#endregion

#region 手动自动重连

//public class MqttClientService : IMqttClientService, IDisposable
//{
//    private readonly ILogger<MqttClientService> _logger;
//    private readonly IOptionsMonitor<MqttSettings> _settings;
//    private IMqttClient? _mqttClient;
//    private MqttClientOptions? _options;
//    private CancellationTokenSource? _reconnectCts;
//    private volatile bool _intentionalStop;
//    public bool IsConnected => _mqttClient?.IsConnected ?? false;

//    public event Func<MqttApplicationMessageReceivedEventArgs, Task>? MessageReceived;

//    public MqttClientService(ILogger<MqttClientService> logger, IOptionsMonitor<MqttSettings> settings)
//    {
//        _logger = logger;
//        _settings = settings;
//    }

//    public async Task StartAsync()
//    {
//        if (_mqttClient?.IsConnected == true) return;

//        _intentionalStop = false;
//        var factory = new MqttClientFactory();
//        _mqttClient = factory.CreateMqttClient();

//        var currentSettings = _settings.CurrentValue;
//        _options = new MqttClientOptionsBuilder()
//            .WithTcpServer(currentSettings.Broker, currentSettings.Port)
//            .WithClientId(currentSettings.ClientId)
//            .WithCredentials(currentSettings.Username, currentSettings.Password)
//            .WithKeepAlivePeriod(TimeSpan.FromSeconds(currentSettings.KeepAlivePeriod))
//            .Build();

//        _mqttClient.ConnectedAsync += OnConnected;
//        _mqttClient.DisconnectedAsync += OnDisconnected;
//        _mqttClient.ApplicationMessageReceivedAsync += OnMessageReceived;

//        await ConnectWithRetry();
//    }

//    private async Task ConnectWithRetry()
//    {
//        while (!_intentionalStop)
//        {
//            try
//            {
//                await _mqttClient!.ConnectAsync(_options!, CancellationToken.None);
//                _logger.LogInformation("MQTT 已连接");
//                return;
//            }
//            catch (Exception ex)
//            {
//                _logger.LogWarning(ex, "MQTT 连接失败,{Delay}秒后重试", _settings.CurrentValue.ReconnectDelaySeconds);
//                await Task.Delay(TimeSpan.FromSeconds(_settings.CurrentValue.ReconnectDelaySeconds));
//            }
//        }
//    }

//    private async Task OnConnected(MqttClientConnectedEventArgs args)
//    {
//        _logger.LogInformation("MQTT 连接成功事件触发");
//        // 订阅默认主题(示例)
//        await _mqttClient!.SubscribeAsync($"{_settings.CurrentValue.TopicPrefix}#");
//    }

//    private async Task OnDisconnected(MqttClientDisconnectedEventArgs args)
//    {
//        _logger.LogWarning("MQTT 断开连接,原因:{Reason}", args.Reason);
//        if (!_intentionalStop)
//        {
//            _ = Task.Run(async () =>
//            {
//                await Task.Delay(1000);
//                await ConnectWithRetry();
//            });
//        }
//    }

//    private async Task OnMessageReceived(MqttApplicationMessageReceivedEventArgs args)
//    {
//        var payload = Encoding.UTF8.GetString(args.ApplicationMessage.Payload);
//        _logger.LogInformation("收到消息 [{Topic}]: {Payload}", args.ApplicationMessage.Topic, payload);
//        if (MessageReceived != null)
//            await MessageReceived.Invoke(args);
//    }

//    public async Task StopAsync()
//    {
//        _intentionalStop = true;
//        if (_mqttClient != null)
//        {
//            _mqttClient.ConnectedAsync -= OnConnected;
//            _mqttClient.DisconnectedAsync -= OnDisconnected;
//            _mqttClient.ApplicationMessageReceivedAsync -= OnMessageReceived;

//            if (_mqttClient.IsConnected)
//                await _mqttClient.DisconnectAsync();
//            _mqttClient.Dispose();
//            _mqttClient = null;
//        }
//    }

//    public async Task PublishAsync(string topic, string payload, bool retain = false)
//    {
//        if (_mqttClient?.IsConnected != true) throw new InvalidOperationException("MQTT 未连接");
//        var message = new MqttApplicationMessageBuilder()
//            .WithTopic(topic)
//            .WithPayload(payload)
//            .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce)
//            .WithRetainFlag(retain)
//            .Build();
//        await _mqttClient.PublishAsync(message);
//        _logger.LogInformation("已发布到 [{Topic}]: {Payload}", topic, payload);
//    }

//    public void Dispose()
//    {
//        _mqttClient?.Dispose();
//        _reconnectCts?.Cancel();
//    }
//}
#endregion
View Code

//// 注册 MQTTnet 5.x 的核心工厂与托管客户端
builder.Services.AddSingleton<MqttClientFactory>();
builder.Services.AddSingleton<IMqttClient>(sp =>
{
    var factory = new MqttClientFactory();
    return factory.CreateMqttClient();
});
builder.Services.AddHostedService<MqttClientService>();
View Code

 

posted @ 2026-05-29 11:10  bxzjzg  阅读(33)  评论(0)    收藏  举报