Is it possible to access server from outside it's handlers, for example to send message from server in some rest endpoint?
I can set server only from app.useMqttSever(server => …) which is anonymous function and I cannot access that server from anywhwere other then it's handlers like receive message or something like that.
I assume, you're using Asp.Net Core? As far as I know, this is not possible. However, I haven't seen any working integration with controllers into Asp.Net yet... I wanted to add this as an example already, but I don't know how to do this.
@JanEggers You seem to be more experienced with the ASP part here...
Hi, thanks for the quick response, yes, I am using Asp.Net Core.
the server is in the di container just add it to the ctor of your controller
I will document this. Might be interesting for others as well.
We have an ASP.NET Core application that needs to send MQTT messages from an MVC controller and we did it by registering an MqttService singleton that can be recovered by DI from any other part of the application. The trick is to have two methods to correctly setup the MQTT part:
1) Have MqttService implement all the interfaces needed to hook with MqttServer (like IMqttServerClientConnectedHandler, IMqttServerApplicationMessageInterceptor, etc.)
2) Write a ConfigureMqttServerOptions(AspNetMqttServerOptionsBuilder options) method that setup the current object as callback for the needed methods, for example we have:
public void ConfigureMqttServerOptions(AspNetMqttServerOptionsBuilder options)
{
options.WithConnectionValidator(this);
options.WithApplicationMessageInterceptor(this);
}
3) Write a ConfigureMqttServer(IMqttServer mqtt) that stores the reference to the MQTT server for later use and, possibly, setup the handlers:
public void ConfigureMqttServer(IMqttServer mqtt)
{
this.mqtt = mqtt;
mqtt.ClientConnectedHandler = this;
mqtt.ClientDisconnectedHandler = this;
}
Then, in your Startup class configure and use the service.
In ConfigureServices:
services.AddSingleton<MqttService>();
services.AddHostedMqttServerWithServices(options => {
var s = options.ServiceProvider.GetRequiredService<MqttService>();
s.ConfigureMqttServerOptions(options);
});
services.AddMqttConnectionHandler();
services.AddMqttWebSocketServerAdapter();
And in Configure:
app.UseMqttEndpoint();
app.UseMqttServer(server => app.ApplicationServices.GetRequiredService<MqttService().ConfigureMqttServer(server));
Hope this helps.
Thanks guys, it works like a charm <3
I will re-open this just for reasons of documentation. I want to create an example project for this and put this to the wiki as well.
Hi there, as you discussed above, is it possible to move the mqtt server from the asp.net core to some windows services or some other console apps? I have some issue when hosting in asp.net core iis that some times it not give any response and the web app in IIS I cannot restart it every time when not responding.
@jasonliaocn just follow the docs https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/windows-service?view=aspnetcore-3.0&tabs=visual-studio
@JanEggers I think this would help if I have only one web app, but actually I have more than one web apps on that server and each have a domain name on the port 80, not sure if I move some apps to the windows services and they will still listen to the 80 port? need to have a try.
I want the asp.net core web app as a client which will send command to a standalone mqtt server, and some other client will consume the commands and execute
I have this code in Startup.cs
`
public void ConfigureServices(IServiceCollection services)
{
//Notificador
services.AddScoped<Business.Interfaces.INotificador, Business.Notificacoes.Notificador>();
services.AddScoped<Business.Interfaces.IRepositorioService, Business.Services.RepositorioService>();
//MQTT
services.AddTransient<MqttService>();
services.AddHostedMqttServerWithServices(options =>
{
var s = options.ServiceProvider.GetRequiredService<MqttService>();
s.ConfigureMqttServerOptions(options);
});
services.AddMqttConnectionHandler();
services.AddMqttWebSocketServerAdapter();
}
`
But the error always occurs:
Cannot resolve 'Automa.Mqtt.Service.MqttService' from root provider because it requires scoped service 'Automa.Business.Interfaces.IRepositorioService'.'
Plase, help me!
@renerlemes For me, this looks like you have a dependency to IRepositorioService in the MqttService. E.g. a direct dependency or a consturctor parameter or something like that?
@SeppPenner
private readonly Business.Interfaces.IRepositorioService _ServiceWrapper;
public MqttService(Business.Interfaces.IRepositorioService serviceWrapper)
{
_ServiceWrapper = serviceWrapper;
}
@renerlemes the issue is service lifetime
Cannot resolve 'Automa.Mqtt.Service.MqttService' from root provider because it requires scoped service 'Automa.Business.Interfaces.IRepositorioService'.'
there are 2 options:
if the MqttService is just for configuring the server i would create a service scope there:
services.AddHostedMqttServerWithServices(options =>
{
using (var scope = options.ServiceProvider.CreateScope())
{
var s = scope.ServiceProvider.GetRequiredService<MqttService>();
s.ConfigureMqttServerOptions(options);
}
});
if the IRepositorioService is used during the lifetime of the mqttserver is should be a singleton.
@JanEggers I did what you recommended and now you have another error. I tried to read the documentation about DI, but I can't at all.
System.InvalidOperationException: 'Cannot solve scoped service' Automa.Mqtt.Service.MqttService 'from root provider.'
The solution is this.
In startup.cs into configure function, put
services.AddSingleton<MqttHostedServer>();
services.AddHostedMqttServer(mqttServerOptions);
//To use into controller
services.AddSingleton<IMqttServer>(s => s.GetService<MqttHostedServer>());
then into the controller declare a var private IMqttServer _mqttserver { get; set; } and the costructor
public RedSpaceController(ICouchDbStore store, IHubContext<RedSpaceHub> hubContext, ILogger<RedSpaceController> logger, IMqttServer mqttserver)
{
_logger = logger;
_hubContext = hubContext;
_store = store;
_mqttserver = mqttserver;
}
This is now documented under https://github.com/chkr1011/MQTTnet/wiki/Tips-and-Tricks#accessing-the-mqtt-server-in-an-aspnet-mvc-controller and https://github.com/chkr1011/MQTTnet/wiki/Server#accessing-the-mqtt-server-in-an-aspnet-mvc-controller.
Thanks to @fogzot.
Most helpful comment
https://github.com/chkr1011/MQTTnet/blob/2918be18c6c6529584cd1d78e09ebb3fc0819e4f/Source/MQTTnet.AspnetCore/ServiceCollectionExtensions.cs#L69
the server is in the di container just add it to the ctor of your controller