Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring MQTTnet.AspNetCore #2103

Open
wants to merge 91 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 64 commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
897c551
Use IConnectionFactory to create ConnectionContext to replace SocketC…
xljiulang Nov 7, 2024
f38cca3
Refactoring AspNetMQTT
xljiulang Nov 12, 2024
d8c94bd
Separate AspNetCoreMqttServerAdapter from MqttConnectionHandler
xljiulang Nov 13, 2024
73502e4
TryAdd IConnectionFactory as Singleton
xljiulang Nov 13, 2024
3a641ab
Add some remarks
xljiulang Nov 13, 2024
91763ae
Add AspNetCoreMqttNetLogger
xljiulang Nov 13, 2024
9c14222
Delayed start of AspNetCoreMqttServer
xljiulang Nov 13, 2024
2372352
Using fields to cache IHttpContextFeature
xljiulang Nov 13, 2024
8d96e19
Update Server_ASP_NET_Samples
xljiulang Nov 13, 2024
ad5c798
Use ActivatorUtilities to create TMQttServerWrapper
xljiulang Nov 13, 2024
7f95f02
Add IMqttServerBuilder
xljiulang Nov 13, 2024
7b44ea2
Add IMqttClientBuilder
xljiulang Nov 13, 2024
73c1365
Conditionally load SocketConnectionFactoryAssembly
xljiulang Nov 13, 2024
2c10d2c
Add LICENSE
xljiulang Nov 13, 2024
6cda003
DynamicallyAccessedMembers
xljiulang Nov 13, 2024
faaadbd
Inject IOptions<MqttServerOptionsBuilder>
xljiulang Nov 13, 2024
13c9198
Change the namespace to MQTTnet.AspNetCore
xljiulang Nov 13, 2024
b8d8abb
await for_aspNetCoreMqttServer.StartAsync
xljiulang Nov 14, 2024
64ed638
enable Nullable
xljiulang Nov 14, 2024
3526212
Always dispose _connection of AspNetCoreMqttChannelAdapter
xljiulang Nov 14, 2024
b4b0b04
UseTls
xljiulang Nov 14, 2024
d9e02ce
Restore the IMqttClientAdapterFactory interface
xljiulang Nov 15, 2024
b5019bd
Calculate the property values ​​when constructing MqttChannel
xljiulang Nov 15, 2024
c206a4a
MqttServerChannelAdapter is modified to inherit MqttChannel
xljiulang Nov 15, 2024
0a216a9
Add ClientConnectionContext.WebSocket
xljiulang Nov 15, 2024
580257a
Add LICENSE
xljiulang Nov 15, 2024
4f6b7ae
Add support for CreateLowLevelMqttClient
xljiulang Nov 15, 2024
b25159b
AddMqttClient: Use AspNetCoreMqttClientAdapterFactory as the default …
xljiulang Nov 16, 2024
ecb404f
Check that UseMqtt() and MapMqtt() are used.
xljiulang Nov 16, 2024
858a914
AspNetCoreMqttServerAdapter: Logging when MqttServerOptions are ignored
xljiulang Nov 16, 2024
fedb631
Add IMqttServerBuilder.AddMqttServerAdapter() extensions
xljiulang Nov 16, 2024
67239cd
Register MqttServerOptions and MqttServerStopOptions as services
xljiulang Nov 16, 2024
e03b9b1
IMqttBuilder: Add IMqttBuilder.UseAspNetCoreMqttNetLogger() extension
xljiulang Nov 16, 2024
014a50b
Remove some dead code.
xljiulang Nov 16, 2024
ad62877
Apply the properties of MqttClientTcpOptions to the Socket
xljiulang Nov 16, 2024
c49beb0
TlsConnectionFeature supports passing in ClientCertificate
xljiulang Nov 17, 2024
4c55368
Add support for MqttPacketInspector
xljiulang Nov 17, 2024
34a4db2
Add route syntax for pattern parameter.
xljiulang Nov 17, 2024
6dc18e1
Add KestrelServerOptions.ListenMqtt() extensions.
xljiulang Nov 17, 2024
67dfda4
Optimize the implementation of ListenMqtt.
xljiulang Nov 17, 2024
5813a13
Adapt MqttServerTlsTcpEndpointOptions to HttpsConnectionAdapterOptions
xljiulang Nov 17, 2024
7628614
Compatible with the default server certificate.
xljiulang Nov 17, 2024
7d8562a
Supports both MQTT and MQTT over WebSocket on a ConnectionContext.
xljiulang Nov 18, 2024
1bd5949
MqttProtocols adds WebSocket item.
xljiulang Nov 18, 2024
c4d9a22
Make sure services.AddMqttServer() has been called before operating M…
xljiulang Nov 18, 2024
62313c8
Simplify MqttConnectionMiddleware
xljiulang Nov 18, 2024
e087acb
Improve the compatibility of wss connections.
xljiulang Nov 18, 2024
db4614c
Update UnixSocket sample.
xljiulang Nov 18, 2024
acf8ed7
Update benchmark
xljiulang Nov 18, 2024
457dcc1
Enhanced IOptions of MQTT ServiceOptions
xljiulang Nov 19, 2024
358c2c0
add IMqttServerBuilder.ConfigureMqttSocketTransport extension.
xljiulang Nov 19, 2024
02778aa
Simplifying MqttOptionsFactory
xljiulang Nov 19, 2024
b46b357
Optimizing MqttChannel.SendPacketAsync
xljiulang Nov 19, 2024
38eb1c3
Check buffer IsEmpty.
xljiulang Nov 20, 2024
f953d6d
Merge branch 'dotnet:master' into master
xljiulang Nov 30, 2024
ef838f8
Register MqttClientFactory as a service.
xljiulang Nov 30, 2024
fcad255
Merge branch 'dotnet:master' into master
xljiulang Dec 1, 2024
72b42d5
MqttOptionsFactory.Build() -> MqttOptionsFactory.CreateOptions()
xljiulang Dec 2, 2024
b40c8a1
Add MqttBufferWriterPool
xljiulang Dec 2, 2024
4305ad7
Merge branch 'dotnet:master' into master
xljiulang Dec 2, 2024
cb68a13
Merged from the master branch.
xljiulang Dec 2, 2024
a2c014f
Adapt the RemoteEndPoint property.
xljiulang Dec 2, 2024
dad4faa
Add MqttBufferWriterPoolOptions
xljiulang Dec 3, 2024
6f60eae
Add more conditions to the pool of MqttBufferWriterPoolOptions.
xljiulang Dec 3, 2024
cc64f95
Merge branch 'main'
xljiulang Dec 4, 2024
54f0b4d
MqttBufferWriterPool: Implementing the IReadOnlyCollection interface.
xljiulang Dec 4, 2024
ee4de82
ConfigureAwait(false)
xljiulang Dec 4, 2024
b708344
MqttChannel: adapt AllowPacketFragmentation option.
xljiulang Dec 4, 2024
13e8190
Fixed the issue that GetRemoteEndPoint did not use the remoteEndPoint…
xljiulang Dec 4, 2024
4bfd77d
Add some unit tests.
xljiulang Dec 4, 2024
9d9dd44
Add more unit test.
xljiulang Dec 4, 2024
8b7c411
MqttBufferWriterPoolOptions: Renaming properties.
xljiulang Dec 4, 2024
8a3624d
Rename and update benchmark.
xljiulang Dec 5, 2024
06f03cb
Add AspNetCoreTestEnvironment to test environments.
xljiulang Dec 6, 2024
146b161
CreateTestEnvironment -> CreateMQTTnetTestEnvironment
xljiulang Dec 6, 2024
83148ca
Remove Google's connection test to avoid Google being blocked by SNI …
xljiulang Dec 6, 2024
41af5c5
AspNetCoreTestEnvironment: Adapt logger.
xljiulang Dec 6, 2024
f94e17a
wait with timeout.
xljiulang Dec 6, 2024
efcd6ab
AspNetCoreTestEnvironment: Adjust all configurations to be consistent…
xljiulang Dec 6, 2024
b035659
MqttChannel: Exception handling remains consistent with MqttChannelAd…
xljiulang Dec 6, 2024
6171c81
CrossPlatformSocket_Tests: create a localhost web server for remote h…
xljiulang Dec 6, 2024
9a7a8bd
Server-side adaptation of AllowPacketFragmentation options.
xljiulang Dec 7, 2024
e01e5f3
Merge implementation of IsAllowPacketFragmentation.
xljiulang Dec 8, 2024
bffe065
Added UseLogger overloaded method and renamed an internal method.
xljiulang Dec 8, 2024
ca5d13d
Add some extension methods to IMqttChannelAdapter.
xljiulang Dec 8, 2024
8ceba5f
Add IAspNetCoreMqttChannel and remove IAspNetCoreMqttChannelAdapter;
xljiulang Dec 9, 2024
b65c176
MapMqtt: Restricted to WebSocket transport protocol.
xljiulang Dec 9, 2024
51fb185
Adapt MqttServerTcpEndpointBaseOptions to the Socket accepted by kest…
xljiulang Dec 9, 2024
79f4f68
SocketOptionName.ReuseAddress can only be used for listening Socket s…
xljiulang Dec 9, 2024
7139431
Accurately detect the DualMode value of listenSocket.
xljiulang Dec 9, 2024
5c6e128
Merge branch 'dotnet:master' into master
xljiulang Dec 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Samples/MQTTnet.Samples.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<NuGetAuditMode>all</NuGetAuditMode>
<NuGetAudit>true</NuGetAudit>
<NuGetAuditLevel>low</NuGetAuditLevel>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<!--<AnalysisLevel>latest-Recommended</AnalysisLevel>-->
</PropertyGroup>

<ItemGroup>
Expand Down
116 changes: 56 additions & 60 deletions Samples/Server/Server_ASP_NET_Samples.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,99 +12,95 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using MQTTnet.AspNetCore;
using MQTTnet.Server;

namespace MQTTnet.Samples.Server;

public static class Server_ASP_NET_Samples
{
static readonly string unixSocketPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "mqtt.socks");

public static Task Start_Server_With_WebSockets_Support()
{
/*
* This sample starts a minimal ASP.NET Webserver including a hosted MQTT server.
*/
var host = Host.CreateDefaultBuilder(Array.Empty<string>())
.ConfigureWebHostDefaults(
webBuilder =>
{
webBuilder.UseKestrel(
o =>
{
// This will allow MQTT connections based on TCP port 1883.
o.ListenAnyIP(1883, l => l.UseMqtt());

// This will allow MQTT connections based on HTTP WebSockets with URI "localhost:5000/mqtt"
// See code below for URI configuration.
o.ListenAnyIP(5000); // Default HTTP pipeline
});

webBuilder.UseStartup<Startup>();
});

return host.RunConsoleAsync();
File.Delete(unixSocketPath);

var builder = WebApplication.CreateBuilder();
builder.Services.AddMqttServer(s => s.WithDefaultEndpoint().WithEncryptedEndpoint());
builder.Services.AddMqttClient();
builder.Services.AddHostedService<MqttClientController>();

builder.WebHost.UseKestrel(kestrel =>
{
// Need ConfigureMqttServer(s => ...) to enable the endpoints
kestrel.ListenMqtt();

// We can also manually listen to a specific port without ConfigureMqttServer()
kestrel.ListenUnixSocket(unixSocketPath, l => l.UseMqtt());
// kestrel.ListenAnyIP(1883, l => l.UseMqtt()); // mqtt over tcp
// kestrel.ListenAnyIP(8883, l => l.UseHttps().UseMqtt()); // mqtt over tls over tcp
});

var app = builder.Build();
app.MapMqtt("/mqtt");
app.UseMqttServer<MqttServerController>();
return app.RunAsync();
}

sealed class MqttController
sealed class MqttServerController
{
public MqttController()
private readonly ILogger<MqttServerController> _logger;

public MqttServerController(
MqttServer mqttServer,
ILogger<MqttServerController> logger)
{
// Inject other services via constructor.
_logger = logger;

mqttServer.ValidatingConnectionAsync += ValidateConnection;
mqttServer.ClientConnectedAsync += OnClientConnected;
}

public Task OnClientConnected(ClientConnectedEventArgs eventArgs)
{
Console.WriteLine($"Client '{eventArgs.ClientId}' connected.");
_logger.LogInformation($"Client '{eventArgs.ClientId}' connected.");
return Task.CompletedTask;
}


public Task ValidateConnection(ValidatingConnectionEventArgs eventArgs)
{
Console.WriteLine($"Client '{eventArgs.ClientId}' wants to connect. Accepting!");
_logger.LogInformation($"Client '{eventArgs.ClientId}' wants to connect. Accepting!");
return Task.CompletedTask;
}
}

sealed class Startup
sealed class MqttClientController : BackgroundService
{
public void Configure(IApplicationBuilder app, IWebHostEnvironment environment, MqttController mqttController)
private readonly IMqttClientFactory _mqttClientFactory;

public MqttClientController(IMqttClientFactory mqttClientFactory)
{
app.UseRouting();

app.UseEndpoints(
endpoints =>
{
endpoints.MapConnectionHandler<MqttConnectionHandler>(
"/mqtt",
httpConnectionDispatcherOptions => httpConnectionDispatcherOptions.WebSockets.SubProtocolSelector =
protocolList => protocolList.FirstOrDefault() ?? string.Empty);
});

app.UseMqttServer(
server =>
{
/*
* Attach event handlers etc. if required.
*/

server.ValidatingConnectionAsync += mqttController.ValidateConnection;
server.ClientConnectedAsync += mqttController.OnClientConnected;
});
_mqttClientFactory = mqttClientFactory;
}

public void ConfigureServices(IServiceCollection services)
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
services.AddHostedMqttServer(
optionsBuilder =>
{
optionsBuilder.WithDefaultEndpoint();
});
await Task.Delay(1000);
using var client = _mqttClientFactory.CreateMqttClient();

// var mqttUri = "mqtt://localhost:1883";
// var mqttsUri = "mqtts://localhost:8883";
// var wsMqttUri = "ws://localhost:1883/mqtt";
var wssMqttUri = "wss://localhost:8883/mqtt";

services.AddMqttConnectionHandler();
services.AddConnections();
var options = new MqttClientOptionsBuilder()
//.WithEndPoint(new UnixDomainSocketEndPoint(unixSocketPath))
.WithConnectionUri(wssMqttUri)
.Build();

services.AddSingleton<MqttController>();
await client.ConnectAsync(options, stoppingToken);
await client.DisconnectAsync();
}
}
}
2 changes: 1 addition & 1 deletion Source/MQTTnet.AspTestApp/MQTTnet.AspTestApp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<NuGetAuditMode>all</NuGetAuditMode>
<NuGetAudit>true</NuGetAudit>
<NuGetAuditLevel>low</NuGetAuditLevel>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
<!--<AnalysisLevel>latest-Recommended</AnalysisLevel>-->
</PropertyGroup>

<ItemGroup>
Expand Down
12 changes: 8 additions & 4 deletions Source/MQTTnet.AspTestApp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@
builder.Services.AddRazorPages();

// Setup MQTT stuff.
builder.Services.AddMqttServer();
builder.Services.AddConnections();
builder.Services.AddMqttServer(s => s.WithDefaultEndpoint().WithDefaultEndpointPort(5000));

var app = builder.Build();
// ListenMqtt
builder.WebHost.UseKestrel(kestrel =>
{
kestrel.ListenMqtt(MqttProtocols.WebSocket);
});

var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
Expand All @@ -29,7 +33,7 @@

app.MapRazorPages();

// Setup MQTT stuff.
// mqtt over websocket
app.MapMqtt("/mqtt");

app.UseMqttServer(server =>
Expand Down
2 changes: 1 addition & 1 deletion Source/MQTTnet.AspTestApp/appsettings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
{
"Logging": {
"LogLevel": {
"Default": "Information",
Expand Down
53 changes: 20 additions & 33 deletions Source/MQTTnet.AspnetCore/ApplicationBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,39 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using MQTTnet.Server;
using System;
using System.Diagnostics.CodeAnalysis;

namespace MQTTnet.AspNetCore;

public static class ApplicationBuilderExtensions
{
[Obsolete(
"This class is obsolete and will be removed in a future version. The recommended alternative is to use MapMqtt inside Microsoft.AspNetCore.Builder.UseEndpoints(...).")]
public static IApplicationBuilder UseMqttEndpoint(this IApplicationBuilder app, string path = "/mqtt")
{
app.UseWebSockets();
app.Use(
async (context, next) =>
{
if (!context.WebSockets.IsWebSocketRequest || context.Request.Path != path)
{
await next();
return;
}

string subProtocol = null;

if (context.Request.Headers.TryGetValue("Sec-WebSocket-Protocol", out var requestedSubProtocolValues))
{
subProtocol = MqttSubProtocolSelector.SelectSubProtocol(requestedSubProtocolValues);
}

var adapter = app.ApplicationServices.GetRequiredService<MqttWebSocketServerAdapter>();
using (var webSocket = await context.WebSockets.AcceptWebSocketAsync(subProtocol).ConfigureAwait(false))
{
await adapter.RunWebSocketConnectionAsync(webSocket, context);
}
});

return app;
}

/// <summary>
/// Get and use <see cref="MqttServer"/>
/// </summary>
/// <remarks>Also, you can inject <see cref="MqttServer"/> into your service</remarks>
/// <param name="app"></param>
/// <param name="configure"></param>
/// <returns></returns>
public static IApplicationBuilder UseMqttServer(this IApplicationBuilder app, Action<MqttServer> configure)
{
var server = app.ApplicationServices.GetRequiredService<MqttServer>();

configure(server);
return app;
}

/// <summary>
/// Active MqttServer's wrapper service
/// </summary>
/// <typeparam name="TMQttServerWrapper"></typeparam>
/// <param name="app"></param>
/// <returns></returns>
public static IApplicationBuilder UseMqttServer<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TMQttServerWrapper>(this IApplicationBuilder app)
{
ActivatorUtilities.GetServiceOrCreateInstance<TMQttServerWrapper>(app.ApplicationServices);
return app;
}
}
29 changes: 29 additions & 0 deletions Source/MQTTnet.AspnetCore/AspNetCoreMqttNetLoggerOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Extensions.Logging;
using MQTTnet.Diagnostics.Logger;
using System;

namespace MQTTnet.AspNetCore
{
public sealed class AspNetCoreMqttNetLoggerOptions
{
public string? CategoryNamePrefix { get; set; } = "MQTTnet.AspNetCore.";

public Func<MqttNetLogLevel, LogLevel> LogLevelConverter { get; set; } = ConvertLogLevel;

private static LogLevel ConvertLogLevel(MqttNetLogLevel level)
{
return level switch
{
MqttNetLogLevel.Verbose => LogLevel.Trace,
MqttNetLogLevel.Info => LogLevel.Information,
MqttNetLogLevel.Warning => LogLevel.Warning,
MqttNetLogLevel.Error => LogLevel.Error,
_ => LogLevel.None
};
}
}
}
18 changes: 0 additions & 18 deletions Source/MQTTnet.AspnetCore/AspNetMqttServerOptionsBuilder.cs

This file was deleted.

21 changes: 0 additions & 21 deletions Source/MQTTnet.AspnetCore/BufferExtensions.cs

This file was deleted.

17 changes: 15 additions & 2 deletions Source/MQTTnet.AspnetCore/ConnectionBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,27 @@
// See the LICENSE file in the project root for more information.

using Microsoft.AspNetCore.Connections;
using Microsoft.Extensions.DependencyInjection;
using MQTTnet.Server;

namespace MQTTnet.AspNetCore
{
public static class ConnectionBuilderExtensions
{
public static IConnectionBuilder UseMqtt(this IConnectionBuilder builder)
/// <summary>
/// Handle the connection using the specified MQTT protocols
/// </summary>
/// <param name="builder"></param>
/// <param name="protocols"></param>
/// <returns></returns>
public static IConnectionBuilder UseMqtt(this IConnectionBuilder builder, MqttProtocols protocols = MqttProtocols.MqttAndWebSocket)
{
return builder.UseConnectionHandler<MqttConnectionHandler>();
// check services.AddMqttServer()
builder.ApplicationServices.GetRequiredService<MqttServer>();
builder.ApplicationServices.GetRequiredService<MqttConnectionHandler>().UseFlag = true;

var middleware = builder.ApplicationServices.GetRequiredService<MqttConnectionMiddleware>();
return builder.Use(next => context => middleware.InvokeAsync(next, context, protocols));
}
}
}
Loading
Loading