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

Conversation

xljiulang
Copy link
Contributor

@xljiulang xljiulang commented Nov 14, 2024

After several submissions, I have implemented the following refactorings. See also #2101

IMqttBuilder

IMqttBuilder is used to provide common functions for build MqttServer and MqttClient, such as logging.

public interface IMqttBuilder
{
    IServiceCollection Services { get; }
}

Extensions

public static IMqttBuilder UseMqttNetNullLogger(this IMqttBuilder builder);

public static IMqttBuilder UseAspNetCoreMqttNetLogger(this IMqttBuilder builder);

public static IMqttBuilder UseLogger<TLogger>(this IMqttBuilder builder)where TLogger : class, IMqttNetLogger; 

IMqttServerBuilder

public interface IMqttServerBuilder : IMqttBuilder
{
}

Extensions

public static IMqttServerBuilder AddMqttServer(this IServiceCollection services);
    
public static IMqttServerBuilder ConfigureMqttServer(this IMqttServerBuilder builder, Action<MqttServerOptionsBuilder> configure);

public static IMqttServerBuilder ConfigureMqttServerStop(this IMqttServerBuilder builder, Action<MqttServerStopOptionsBuilder> configure);

public static IMqttServerBuilder AddMqttServerAdapter<TMqttServerAdapter>(this IMqttServerBuilder builder); 

IMqttClientBuilder

public interface IMqttClientBuilder: IMqttBuilder
{ 
}

Extensions

public static IMqttClientBuilder AddMqttClient(this IServiceCollection services);

public static IMqttClientBuilder UseMQTTnetMqttClientAdapterFactory(this IMqttClientBuilder builder);

public static IMqttClientBuilder UseAspNetCoreMqttClientAdapterFactory(this IMqttClientBuilder builder);

public static IMqttClientBuilder UseMqttClientAdapterFactory<TMqttClientAdapterFactory>(this IMqttClientBuilder builder) where TMqttClientAdapterFactory : class, IMqttClientAdapterFactory;

New implementation of IMqttClientAdapterFactory

The SocketConnection that the original MqttClientConnectionContextFactory depends on is a copy of the early code of the kestrel project. It is now deleted and replaced by the IConnectionFactory service of Asp.NetCore to create ConnectionContext instead of SocketConnection ClientConnectionContext, which is a wrapper class for Stream and now supports TCP, TLS, WS and WSS. See also #2104 #2105

IConnectionFactory only provides an asynchronous ConnectAsync() method. In order to call this asynchronous method, we need to modify the CreateClientAdapter method of IMqttClientAdapterFactory to ValueTask<IMqttChannelAdapter> CreateClientAdapterAsync().

Now, the implementation type of IMqttClientAdapterFactory is AspNetCoreMqttClientAdapterFactory, which is an internal modified type and is used by users through IMqttClientBuilder.UseAspNetCoreMqttClientAdapterFactory().

The dependency chain is IMqttClientAdapterFactory-->AspNetCoreMqttClientAdapterFactory-->MqttClientChannelAdapter-->MqttChannel-->ClientConnectionContext

Split MqttHostedServer

MqttHostedServer acts as both MqttServer and HostedService, which makes it difficult to register the service and start the service background.

It has now been split into AspNetCoreMqttServer and AspNetCoreMqttHostedServer. AspNetCoreMqttHostedServer inherits BackgroundService. In its ExecuteAsync method, it waits for the application to start and then starts AspNetCoreMqttServer. #2102

Split MqttConnectionHandler

MqttConnectionHandler no longer implements the IMqttServerAdapter interface. The implementation type of IMqttServerAdapter is AspNetCoreMqttServerAdapter.

The dependency chain is IMqttServerAdapter-->AspNetCoreMqttServerAdapter-->MqttConnectionHandler-->MqttServerChannelAdapter-->MqttChannel-->Kestrel ConnectionContext

Add MqttBufferWriterPool in server mode

MqttBufferWriterPool pools the MqttBufferWriters of channels whose lifecycles are less than one minute to reduce the number of MqttBufferWriters created when clients frequently connect and disconnect.

Add MqttConnectionMiddleware

MqttConnectionMiddleware allows a single port to support both mqtt and mqtt-overt-websocket protocols. It is ultimately applied by IConnectionBuilder.UseMqtt(MqttProtocols).

Add KestrelServerOptions.ListenMqtt(MqttProtocols) extensions

This extension perfectly adapts the listening options of MqttServerOptions to kestrel, allowing users to continue to use the familiar MqttServerOptionsBuilder. In addition, we also provide enhanced httpsOptions configuration.

Make all implementation types internal

Now all implementation types have been modified to internal, and use InternalsVisibleToAttribute to expose them to the specified assembly.

Logger

The new AspNetCoreMqttNetLogger type is now the default IMqttNetLogger, which writes log content to Microsoft.Extensions.Logging.

Nullable

Nullable feature is enabled.

UnitTest

The new AspNetCoreTestEnvironment is added to the test environment and participates in the test at the same time as the default TestEnvironment.

Exception

Now the exception types and exception behaviors of MqttChannel are exactly the same as those of MqttChannelAdapter.

@xljiulang
Copy link
Contributor Author

@dotnet-policy-service agree

@xljiulang
Copy link
Contributor Author

The development of this PR has been completed and has passed the same one-sided tests as MQTTnet(Client) and MQTTnet.Server.
In the future, after #2109 is merged into the master branch, the new method of MqttPacketInspector can be continued to be adapted to reduce memory allocation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants