Abp vNext 集成 MQTT
Broker
ApsNet Core 集成 MQTT
引用包
<PackageReference Include="MQTTnet.AspNetCore" Version="3.1.2" />
添加服务
代码清单:Artisan.IotHub.HttpApi.Host/IotHubHttpApiHostModule.cs
public override void ConfigureServices(ServiceConfigurationContext context)
{
// ......
ConfigureMqttService(context, configuration);
}
private void ConfigureMqttService(ServiceConfigurationContext context, IConfiguration configuration)
{
var settings = configuration.GetSection("MqttServer").Get<MqttServerSettings>();
context.Services.ConfigureMqttService(settings);
}
appsettings.json 中的配置:
"MqttServer": {
"IpAddress": "localhost",
"DomainName": "",
"Port": 2883,
"EnableTls": false,
"TlsPort": 8883
},
其中:
方法 ConfigureMqttServic()
是扩展方法,如下所示:
代码清单:Artisan.IotHub.Application/Mqtts/Extensions/MqttConfiguration.cs
public static class MqttConfiguration
{
public static void ConfigureMqttService(
this IServiceCollection services,
MqttServerSettings settings)
{
services.AddHostedMqttServerWithServices(options =>
{
options.WithDefaultEndpointPort(settings.Port).WithDefaultEndpoint();
var mqttService = services.GetRequiredService<MqttServerService>();
mqttService.ConfigureMqttServerOptions(options);
});
services.AddMqttConnectionHandler();
services.AddMqttWebSocketServerAdapter();
services.AddConnections();
}
// .....
}
添加 MQTT Endpoint
代码清单:Artisan.IotHub.HttpApi.Host/IotHubHttpApiHostModule.cs
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
app.UseAbpRequestLocalization();
app.UseCorrelationId();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
// 添加 MQTT 中间件
app.UseMqttServer();
app.UseSwagger();
}
其中:方法UseMqttServe()
是自定义的扩展方法,如下所示:
代码清单:Artisan.IotHub.Application/Mqtts/Extensions/MqttConfiguration.cs
public static class MqttConfiguration
{
//......
public static void UseMqttServer(this IApplicationBuilder app)
{
app.UseMqttServer(mqttServer =>
{
app.ApplicationServices
.GetRequiredService<MqttServerService>()
.ConfigureMqttServer(mqttServer);
});
app.UseEndpoints(endpoint =>
{
endpoint.MapMqtt("/mqtt");
});
}
}
ConfigureMqttServer()调用:
代码清单:Artisan.IotHub.Application/Mqtts/MqttServerService.cs
public class MqttServerService : IMqttServerService, ISingletonDependency
{
private readonly IMqttConnectionService _mqttConnectionService;
private readonly IMqttSubscriptionService _mqttSubscriptionService;
private readonly IMqttPublishingService _mqttPublishingService;
public MqttServerService(
IMqttConnectionService mqttConnectionService,
IMqttSubscriptionService mqttSubscriptionService,
IMqttPublishingService mqttPublishingService)
{
_mqttConnectionService = mqttConnectionService;
_mqttSubscriptionService = mqttSubscriptionService;
_mqttPublishingService = mqttPublishingService;
}
public void ConfigureMqttServer(IMqttServer mqttServer)
{
_mqttConnectionService.ConfigureMqttServer(mqttServer);
_mqttSubscriptionService.ConfigureMqttServer(mqttServer);
_mqttPublishingService.ConfigureMqttServer(mqttServer);
}
public void ConfigureMqttServerOptions(AspNetMqttServerOptionsBuilder options)
{
_mqttConnectionService.ConfigureMqttServerOptions(options);
_mqttSubscriptionService.ConfigureMqttServerOptions(options);
_mqttPublishingService.ConfigureMqttServerOptions(options);
options.WithoutDefaultEndpoint();
}
}
设置 MQTT监听端口
通过ConfigureKestrel()方法在 Kestrel 上设置MQTT的监听端口,如下代码所示:
代码清单:Artisan.IotHub.HttpApi.Host/Program.cs
var builder = WebApplication.CreateBuilder(args);
// ......
builder.WebHost.ConfigureKestrel(option =>
{
option.ConfigureMqttServer();
});
其中:方法 ConfigureMqttServer()
是扩展方法,如下所示:
代码清单:Artisan.IotHub.HttpApi.Host/KestrelServerOptionsExtensions.cs
public static class KestrelServerOptionsExtensions
{
/// <summary>
/// 在 KestrelServer 中设置 MqttServer 的监听端口
/// </summary>
/// <param name="option"></param>
public static void ConfigureMqttServer(this KestrelServerOptions option)
{
var configuration = option.ApplicationServices.GetRequiredService<IConfiguration>();
var mqttSettings = configuration.GetSection("MqttServer").Get<MqttServerSettings>();
//option.ListenAnyIP(mqttSettings.Port, opt => opt.UseMqtt());
if (mqttSettings.IpAddress.ToLower() == "localhost")
{
option.ListenLocalhost(mqttSettings.Port, opt => opt.UseMqtt());
}
else
{
option.Listen(
IPAddress.Parse(mqttSettings.IpAddress),
mqttSettings.Port, opt => opt.UseMqtt()
);
}
}
}
修复 Http和Https 的监听端口
通过ConfigureKestrel()方法在 Kestrel 上设置MQTT的监听端口,如下代码所示:
builder.WebHost.ConfigureKestrel(option =>
{
option.ConfigureMqttServer();
});
=> option.Listen(
IPAddress.Parse(mqttSettings.IpAddress),
mqttSettings.Port, opt => opt.UseMqtt()
);
但是这样做,会出现一个Bug:Http和Https 的监听端口将会失效 !!!,
通过Http和Https 监听端口(比如:https://localhost:44359)是无法访问 Api的。
原因:
通过 ConfigureKestrel() 方法在 Kestrel 上设置的Http和Https 监听端口后,其它地方设置(例如:在launchSettings.json 文件)的监听方式会被覆盖而失效!
而我们又没有在ConfigureKestrel()的方法中重新设置Http和Https 的监听端口。
在日志中也能看到提示警告:
[11:17:46 WRN] Overriding address(es) 'https://localhost:44359'. Binding to endpoints defined via IConfiguration and/or UseKestrel() instead.
如何修复呢?
可通过修改配置文件appsettings.json
来设置Http和Https的监听端口,具体操作如下:
在配置文件appsettings.json
中添加如下 Kestrel 配置节点:
{
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:7059",
"Protocols": "Http1AndHttp2"
},
"Https": {
"Url": "https://localhost:44359",
"Protocols": "Http1AndHttp2"
},
}
}
// .....
}
这样就通过配置文件的方式为Kestrel 设置了Http和Https的监听端口