Adding SignalR service as a singleton and then adding redis to it - asp.net-core

Hello i have an app up and running using orleans and signalR and i use a HubConnectionBuilder to initialize my SignalRClient like this
public async Task<HubConnection> InitSignalRCLient()
{
Program.WriteConsole("Starting SignalR Client...");
var connection = new HubConnectionBuilder()
.ConfigureLogging(logging =>
logging
.AddProvider(new LogProvider(Log.logger, new LogProviderConfiguration
{
Category = LogCategory.SignalR,
Level = LogLevel.Warning
}))
)
.WithUrl(Configuration.GetConnectionString("SignalRInterface"))
.Build();
And then i add the service as a singleton in the configure service
services.AddSingleton(SignalRClient)
The problem is now that i want to use redis as a backplane to this and i am having issues adding the redis service to my current way of using SignalR
like this doesn't work
services.AddSingleton(SignalRClient).AddStackExchangeRedis();
according to the documentation https://learn.microsoft.com/en-us/aspnet/core/signalr/redis-backplane?view=aspnetcore-2.2 it wants you to add it like
services.AddSignalR().AddStackExchangeRedis("<your_Redis_connection_string>");
but that doesn't work with how i use SignalR. Is there anyway to get my implementation to work or anyone got any advice on how to tackle this?

Try to add in ConfigureServices this:
services.AddDistributedRedisCache(option =>
{
option.Configuration = Configuration.GetConnectionString(<your_Redis_connection_string>);
});
services.AddSignalR().AddStackExchangeRedis(Configuration.GetConnectionString(<your_Redis_connection_string>));
Also add this in Configure
app.UseSignalR(routes =>
{
routes.MapHub<your_Hub>("/yourHub");
});
And don't forget add abortConnect=False in connectionStrings

Related

ServiceStack - IAuthRepository vs IUserAuthRepository

I’ve to configure my web application to use the ServiceStack built-in ApiKeyAuthProvider. I’ve registered in the container the OrmLiteAuthRepository with the IAuthRepository interface but it throws an exception saying that I’ve not registered the IUserAuthRepository.
Could someone explain me the difference?
Thanks in advance
EDIT:
Sorry, i've made confusion
The error is
System.NotSupportedException: 'ApiKeyAuthProvider requires a registered IAuthRepository'
Our AppHost's Configure method is
public override void Configure(Container container)
{
var dbFactory = new OrmLiteConnectionFactory("connString", SqlServerDialect.Provider);
container.Register<IDbConnectionFactory>(dbFactory);
container.Register<IUserAuthRepository>(_ => new OrmLiteAuthRepository(dbFactory));
container.Resolve<IUserAuthRepository>().InitSchema();
var authProvider = new ApiKeyAuthProvider()
{
RequireSecureConnection = false
};
Plugins.Add(new AuthFeature(
() => new AuthUserSession(),
new IAuthProvider[] {
authProvider
}
));
}
Could you explain me the difference between these two interfaces? we can't figure out (ServiceStack v.6.0.2)
Please refer to the Auth Repository docs for examples of correct usage, e.g:
container.Register<IDbConnectionFactory>(c =>
new OrmLiteConnectionFactory(connectionString, SqlServer2012Dialect.Provider));
container.Register<IAuthRepository>(c =>
new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>()));
container.Resolve<IAuthRepository>().InitSchema();
The IAuthRepository is the minimum interface all Auth Repositories have to implement whilst IUserAuthRepository is the extended interface to enable extended functionality to enabled additional features which all ServiceStack built-in Auth Repositories also implement. But you should never need to register or resolve a IUserAuthRepository, i.e. they should only be registered against the primary IAuthRepository interface.
Resolving Auth Repository
If you need to, the Auth Repository can be accessed from base.AuthRepository or base.AuthRepositoryAsync in your Service where you'll be able to use any IUserAuthRepository APIs since they're all available as extension methods on IAuthRepository, e.g. This example Service calls the IUserAuthRepository.GetUserAuth() method:
public class MyServices : Service
{
public object Get(MyRequest request) =>
AuthRepository.GetUserAuth(request.UserId);
}
Whilst here are the recommended APIs to access the Auth Repository outside of your Services:
var authRepo = HostContext.AppHost.GetAuthRepository();
var authRepoAsync = HostContext.AppHost.GetAuthRepositoryAsync();

MQTTnet Connection Issue with HiveMQ Cloud

I am new to the MQTT world and I am trying to create a .Net 5.0 application that connects to a HiveMQ Cloud Broker.
I have created a free broker and I am able to connect to it with HiveMQ Websocket Client.
Here is a screenshot of my host.
I have created MQTT credentials for the host and I am able to connect over the sample client. Here is a screenshot of that client.
This works, I can publish and subscribe to the message queue.
However, now I am trying to translate this to c# and I am not able to connect. I am starting with this example project: https://github.com/rafiulgits/mqtt-client-dotnet-core
Then plugged the values from my cluster instance but I am a getting connection timeout on startup.
Here is what my service configuration looks like:
public static IServiceCollection AddMqttClientHostedService(this IServiceCollection services)
{
services.AddMqttClientServiceWithConfig(aspOptionBuilder =>
{
//var clientSettinigs = AppSettingsProvider.ClientSettings;
//var brokerHostSettings = AppSettingsProvider.BrokerHostSettings;
aspOptionBuilder
.WithCredentials("Test1", "xxxxx") //clientSettinigs.UserName, clientSettinigs.Password)
.WithClientId("clientId-jqE8uIw6Pp") //clientSettinigs.Id)
.WithTcpServer("xxxxxxxxxxxxxx.s2.eu.hivemq.cloud", 8884); //brokerHostSettings.Host, brokerHostSettings.Port);
});
return services;
}
private static IServiceCollection AddMqttClientServiceWithConfig(this IServiceCollection services, Action<AspCoreMqttClientOptionBuilder> configure)
{
services.AddSingleton<IMqttClientOptions>(serviceProvider =>
{
var optionBuilder = new AspCoreMqttClientOptionBuilder(serviceProvider);
configure(optionBuilder);
return optionBuilder.Build();
});
services.AddSingleton<MqttClientService>();
services.AddSingleton<IHostedService>(serviceProvider =>
{
return serviceProvider.GetService<MqttClientService>();
});
services.AddSingleton<MqttClientServiceProvider>(serviceProvider =>
{
var mqttClientService = serviceProvider.GetService<MqttClientService>();
var mqttClientServiceProvider = new MqttClientServiceProvider(mqttClientService);
return mqttClientServiceProvider;
});
return services;
}
I am not sure where I am going wrong, any help would be greatly appreciated.
You appear to be trying to connect to the WebSocket endpoint (port 8884) in your code, when I suspect you really should be using the normal TLS endpoint (port 8883)
Also you will need to use different clientid values if you want to have both clients connected at the same time as having matching will mean the clients will continuously kick each other off the broker.
(edit: on looking closer the client ids are actually different, but only in the last char)
I had this issue in two days ago and it seems coming form TLS confgurations/settings. By the way, my Startup.cs service injections and some configurations were same with yours. I have .NetCore app and I am trying to connect my own hivemq broker (cloud side).
In this case we need to add additional option to our mqtt client option build phase.
When I add this code, Auth problems gone.
.WithTls();
Here is part of the client option codes should like that
AddMqttClientServiceWithConfig(services,optionBuilder =>
{
var clientSettings = BrokerAppSettingsProvider.BrokerClientSettings;
var brokerHostSettings = BrokerAppSettingsProvider.BrokerHostSettings;
optionBuilder
.WithCredentials(clientSettings.UserName, clientSettings.Password)
.WithTls()
.WithTcpServer(brokerHostSettings.Host, brokerHostSettings.Port);
});
return services;
We can consider this as a different solution.

Migration to Minimal API - Test Settings Json not overriding Program

Thanks to this answer: Integration test and hosting ASP.NET Core 6.0 without Startup class
I have been able to perform integration tests with API.
WebApplicationFactory<Program>? app = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
builder.ConfigureServices(services =>
{
});
});
HttpClient? client = app.CreateClient();
This has worked using the appsettings.json from the API project. Am now trying to use integrationtestsettings.json instead using:
IConfiguration configuration = new ConfigurationBuilder()
.SetBasePath(ProjectDirectoryLocator.GetProjectDirectory())
.AddJsonFile("integrationtestsettings.json")
.Build();
WebApplicationFactory<Program>? app = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder =>
{
builder.ConfigureAppConfiguration(cfg => cfg.AddConfiguration(configuration));
builder.ConfigureServices(services =>
{
});
});
_httpClient = app.CreateClient();
I have inspected the configuration variable and can see the properties loaded from my integrartiontestsettings.json file. However, the host is still running using the appsettings.json from the server project.
Previously, in .Net5, I was using WebHostBuilder and the settings were overridden by test settings.
WebHostBuilder webHostBuilder = new();
webHostBuilder.UseStartup<Startup>();
webHostBuilder.ConfigureAppConfiguration(cfg => cfg.AddConfiguration(_configuration));
But cannot get the test settings to apply using the WebApplicationFactory.
It seems the method has changed.
Changing:
builder.ConfigureAppConfiguration(cfg => cfg.AddConfiguration(configuration));
To:
builder.UseConfiguraton(configuration);
has done the trick.
builder.ConfigureAppConfiguration, now it's configuring the app (after your WebApplicationBuilder.Build() is called) and your WebApplication is created.
You need to "inject" your configurations before the .Build() is done. This is why you need to call UseConfiguraton instead of ConfigureAppConfiguration.

SignalR and Redis

I've got a project that uses SignalR and a RedisBackplane, we've moved from StackExchange.Redis to ServiceStack.Redis due to Redis Sentinel compatibility issues (Not movable)
However, it now looks like the support for SignalR Redis Backplane seems to be tied into StackExchange?
Have I completely missed something, or is there support for ServiceStack on a SignalR Redis Backplane?
Current code looks like:
var redisConnection = ConnectionMultiplexer.Connect(this.Configuration.GetValue<string>("Redis"));
services.AddSignalR(o => { o.EnableDetailedErrors = true; })
.AddStackExchangeRedis(options =>
{
options.Configuration.ChannelPrefix = "Audit";
options.ConnectionFactory =
writer => Task.FromResult(redisConnection as IConnectionMultiplexer);
});
I don't believe anyone has implemented a SignalR Redis backplane using ServiceStack.Redis.
ServiceStack does have it's own real-time events solution using SSE which includes a Redis Server Events implementation that uses ServiceStack.Redis (akin to SignalR Redis backplane).
I prefer to use username/password in the configuration
//StackExchange.Redis for configuration options
var redisConfiguration = new ConfigurationOptions
{
EndPoints = { "serverinfo:portinfo" },
User = username,
Password = password
//,Ssl = true
};
signalRBuilder.AddStackExchangeRedis(options => { options.Configuration = redisConfiguration; });

how to use GetConnectedClientsAsync from MQTTnet.Server in asp.net core

I can host mqtt broker with MQTTnet nuget in asp.net core 2.2 by following code. I just want to show list of connected cliend in my controller and I found that GetConnectedClientsAsync method can be used. But I don't know how to use in core 2.2. Any suggestion.
In ConfigureServices
var mqttServerOption = new MqttServerOptionsBuilder()
.WithDefaultEndpointPort(6261)
.WithConnectionValidator(Mqtt.connectionValidator.validator)
.Build();
services.AddHostedMqttServer(mqttServerOption)
.AddMqttConnectionHandler()
.AddConnections()
.AddMqttTcpServerAdapter();
In Configure
app.UseMqttEndpoint();
finally found the solution.
just added controller constructor
private readonly MQTTnet.AspNetCore.MqttHostedServer mqttHostedServer;
public testController(MQTTnet.AspNetCore.MqttHostedServer mqttHostedServer)
{
this.mqttHostedServer = mqttHostedServer;
}
and I can use it now.
var clients = await mqttHostedServer.GetClientStatusAsync();