SignalR and Redis - 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; });

Related

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.

Can we use RabbitMQ and Mediatr together using masstransit?

I created a microservice application that microservices using MassTransit and RabbitMQ for communication.
Each microservice developed using clean architecture, so we have MediatR inside each microservice.
Is it possible to use MassTransit for inside communication as well? so I can use the same signature for all services and when I want to expose a service to be used inter-microservice, it will be doable with ease.
So MediatR used for intra-communication and RabbitMQ used for inter-communication, and whole universe is on MassTransit system.
[Update] My question is how we can configure consumers so some can be used for inside communication (via MediatR) and some can be used for external communication (via RabbitMQ) and easily change them from inside to outside.
[Update2] for example here is my MassTransit registration:
services.AddMassTransit(x =>
{
x.AddConsumers(Assembly.GetExecutingAssembly());
x.AddBus(provider =>
Bus.Factory.CreateUsingRabbitMq(cfg =>
{
cfg.Host(new Uri(config.RabbitMQ.Address), h =>
{
h.Username(config.RabbitMQ.Username);
h.Password(config.RabbitMQ.Password);
});
cfg.ReceiveEndpoint("my-queue", ep => { ep.ConfigureConsumers(provider); });
}));
x.AddMediator((provider, cfg) => { cfg.ConfigureConsumers(provider); });
});
How can I differ in internal communication and external communication? in other words, how can I register some consumers to MediatR and some to RabbitMQ?
They can be used together, and MassTransit has its own Mediator implementation as well so you can write your handlers once and use them either via the mediator or via a durable transport such as RabbitMQ.
There are videos available that take you through the capabilities, starting with mediator and moving to RabbitMQ.
I found that I should create a separate bus for each. then external services inherit from an interface like IExternalConsumer, so I can separate them form internal ones and add them to related bus:
UPDATED for version 7
// find consumers
var types = AssemblyTypeCache.FindTypes(new[]{Assembly.GetExecutingAssembly()},TypeMetadataCache.IsConsumerOrDefinition).GetAwaiter().GetResult();
var consumers = types.FindTypes(TypeClassification.Concrete | TypeClassification.Closed).ToArray();
var internals = new List<Type>();
var externals = new List<Type>();
foreach (Type type in consumers)
{
if (type.HasInterface<IExternalConsumer>())
externals.Add(type);
else
internals.Add(type);
}
services.AddMediator(x =>
{
x.AddConsumers(internals.ToArray());
x.ConfigureMediator((provider, cfg) => cfg.UseFluentValidation());
});
services.AddMassTransit<IExternalBus>(x =>
{
x.AddConsumers(externals.ToArray());
x.AddBus(provider =>
Bus.Factory.CreateUsingRabbitMq(cfg =>
{
cfg.Host(new Uri(config.RabbitMQ.Address), h =>
{
h.Username(config.RabbitMQ.Username);
h.Password(config.RabbitMQ.Password);
});
cfg.ReceiveEndpoint(apiProviderName, ep => { ep.ConfigureConsumers(provider); });
}));
});
services.AddMassTransitHostedService();

Adding SignalR service as a singleton and then adding redis to it

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

can't handle multiple request using rabbitmq and masstransist in .net core

I am currently working with micro service architecture and .net core.
Rabbit MQ + MassTransit are being used to send and receive data between the micro services.
I have a host application in IIS and from 2 separate browsers I send the same request to micro service and that microservice calls other service using RabbitMQ.
I expect to get 2 separate requests hitting the consumer but instead get an internal server error.
Startup:
services.AddScoped<OrderCompletedEventConsumer>();
services.AddMassTransit(x =>
{
x.AddConsumer<Controllers.OrderController>();
});
services.AddSingleton(provider => Bus.Factory.CreateUsingRabbitMq(cfg =>
{
var host = cfg.Host(new Uri("http://192.168.101.111:5672"),
"/", h =>
{
h.Username("Test");
h.Password("test");
});
cfg.ReceiveEndpoint(host, "TestQUE", e =>
{
e.Consumer<Controllers.OrderController>(provider);
});
}));
//Register Publish Endpoint of RabbitMQ bus service
services.AddSingleton<IPublishEndpoint>(provider => provider.GetRequiredService<IBusControl>());
//Register Send Endpoint of RabbitMQ bus service
services.AddSingleton<ISendEndpointProvider>(provider => provider.GetRequiredService<IBusControl>());
//Register Bus control for RabbitMQ
services.AddSingleton<IBus>(provider => provider.GetRequiredService<IBusControl>());
//Regster Bus Service hosting
services.AddSingleton<IHostedService, BusService>();
Request From One microservice:-
IRequestClient<IAddRequest<IOrder>, IAddResponse<IOrder>> orderClient =
new MessageRequestClient<IAddRequest<IOrder>, IAddResponse<IOrder>>(_bus,
EndpointAddress("orderQue"), TimeSpan.FromSeconds(Convert.ToDouble("150")));
var addResponse = orderClient.Request(new
{
entity = order
});
await Task.WhenAll(addResponse);
Consumer
public async Task Consume(ConsumeContext<IGetRequest<IOrder>> context)
{
// Operation and return result
await context.RespondAsync<IGetResposne<IOffice>>(new
{
// send result.
});
}
In the consumer the 2 separate requests from different browser arrive but both are unsuccessful. However if I do one request at a time then it will work, why is this?
Please give any idea, suggestion or hint.
Thank you,

Akka.net cluster broadcast only received by one node

I learned from the Akka.net WebCrawler and created my own cluster test. I have a Processor node(Console App) and an API node(SignalR). Here are the configurations.
Processor node:
akka {
actor{
provider = "Akka.Cluster.ClusterActorRefProvider, Akka.Cluster"
deployment {
/dispatcher/signalR {
router = broadcast-group
routees.paths = ["/user/signalr"]
cluster {
enabled = on
#max-nr-of-instances-per-node = 1
allow-local-routees = false
use-role = api
}
}
}
}
remote {
log-remote-lifecycle-events = DEBUG
helios.tcp {
port = 0
hostname = 127.0.0.1
}
}
cluster {
seed-nodes = ["akka.tcp://stopfinder#127.0.0.1:4545"]
roles = [processor]
}
}
API node: (Non seed-node will have port = 0)
akka {
actor{
provider = "Akka.Cluster.ClusterActorRefProvider, Akka.Cluster"
}
remote {
log-remote-lifecycle-events = DEBUG
helios.tcp {
port = 4545
hostname = 127.0.0.1
}
}
cluster {
seed-nodes = ["akka.tcp://stopfinder#127.0.0.1:4545"]
roles = [api]
}
}
Inside of the API node, I created a normal actor called SignalR.
Inside of the processor node I created a normal actor and used the Scheduler to Tell() the API node's signalR actor some string.
This works great when I have one Processor and one API. It also works when I have multiple Processor nodes and a single API node. Unfortunately, when I have multiple API node, no matter how I setup the configuration, the "tell" won't tell all of the API nodes; the message only goes to one of them. Which node receives the message is based on the API node start sequence. It seems that I have the all API nodes registered in the cluster correctly, but I could be wrong.
I'm starting to feel that this is a configuration or understanding issue. Can anyone share any insights?
I did some additional testing. The behavior remains the same when I replace the ASP.NET SignalR API node with a normal console application.
UPDATE: I contacted Akka.NET team. This behavior is a known bug. It will be fixed in 1.1 release.
UPDATE 2: The issue has been marked as fixed for the proejct on GitHub.