Using SignalR HubContext in ASP.NET Core Project - c#

I'm starting to use SignalR in my ASP.NET Core project targeting .NET 7.
Currently, the clients are not receiving the message pushed by SignalR but I'm not receiving any errors either. Clients just don't receive anything. As I troubleshoot this, I want to make sure I'm using IHubContext correctly.
I understand that I can use the SignalR IHubContext in my controllers and be able to access my methods that are in the hub and I'm doing that using the code below. My question is about making sure the IHubContext is injected properly and available in my controllers.
Currently, all I do in my Program.cs are as follows -- see below. Is there anything else I need to do to make sure IHubContext is available in my controllers?
app.UseWebSockets();
app.UseSignalRQueryStringAuth();
app.MapHub<MyHub>("/myhub");
And I use the IHubContext as follows in my controller:
public class MyController : ControllerBase
{
private readonly IHubContext<MySignalRHub> _myHub;
public MyController(IHubContext<MySignalRHub> myHub)
{
_myHub = myHub;
}
[HttpPost("dosomething")]
public async Task<IActionResult>DoSomething()
{
// Do something here
// Then notify connected clients using SignalR
await _myHub.SomeMethod("Something new happened!");
}
}

Related

Web service vs Web API (What's the real difference)

Can someone explain me the difference between Web services & web API? I have gone through so many blogs but all of them seems to be using the same bookish knowledge. What's the actual difference between them in real terms?
As #Dai explained the zest and I completely agree with him. In addition, I would like to provide you some real-life difference besides.
Web Service:
As Web Service basically, used WSDL which used to communicate with SOAP or XML base service. However, the main challenge in Web Service was to handle cross-platform request. We used to add service reference as following way: While developped Web Services.
Web API:
Considering these drawbacks, Microsoft, latter on developed the Web API more specifically, Asp.net Web API which provide the robust functionality for cross platform development using REST pattern mostly used Json data. It doesn’t mean that web service cannot do that, but not robust as Web API now a days. Unlike, web service we don’t need to go through any integration hassle as above which we can directly develop using asp.net core project and can open the route to call from anywhere.For instance below example:
[ApiController]
[Route("api/VehicleFilter")]
public class VehicleFilterController : ControllerBase
{
private readonly ApplicationDbContext _context;
private readonly IWebHostEnvironment _environment;
public VehicleFilterController(IWebHostEnvironment environment, ApplicationDbContext context)
{
_environment = environment;
_context = context;
}
[HttpGet]
public async Task<IActionResult> GetAllFilter()
{
string VehicleName = "Hatchback";
var sqlCommand = $"EXEC GetVehicleByTile {VehicleName}";
var vehicleFilterValues = await _context.VehicleFilter.FromSqlRaw(sqlCommand).ToListAsync();
return Ok(vehicleFilterValues);
}
}
To summarize, Web API provides more flexibility and robustness and of course its lightweight while writing any new method. Where web service leads to some demerits to the developer.

Prevent collisions when working with RabbitMq from two or more instances of the same app

Good time, Stack Overflow community.
I have some questions about software architecture i'm working on and i will appreciate for help with them.
The components of the app are following:
Model project (net core class library). Here i define model classes & database context.
Business project (net core class library). It has reference on the Model assembly and implements business logic. Also here, placed a HostedService with code for working with microservices through EasyNetQ using Send/Receive & Request/Response patterns.
Web API project (net core web api app). It uses Business assembly and provides web api features. This app hosted on iis 10.
Web frontend project (net core razor web app). It also uses Business assembly and provides web UI features. This app hosted on iis 10.
Some microservice apps, that may communicate with Business assembly through EasyNetQ by receiving and sending messages. Every microservice runs in the one instance.
Web api app and web frontend app both working simultaneously. So we have two instances of business logic assembly working at the same time and both of them works with the same rabbitmq queues.
So, i'm afraid that one instance of Business assembly may send message to microservice (IBus.Send), but second instance of Business assembly may receive the message from microservice (IBus.Receive). In this case, as i understand, may be collision because the first instance of Business waits answer and does not receive it, at the same time second instance of Business receives not waitable answer.
A bit of code.
Web api app startup:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddBusiness(Configuration);
...
}
Web frontend app startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddBusiness(Configuration);
...
}
Business logic assembly startup:
public static IServiceCollection AddBusiness(this IServiceCollection services, IConfiguration configuration)
{
...
services.AddSingleton(sp =>
{
var rabbitMqSettings = sp.GetRequiredService<IOptions<RabbitMqSettings>>();
return RabbitHutch.CreateBus(rabbitMqSettings.Value.Connection);
});
services.AddHostedService<RabbitMessagesReceiverService>();
return services;
}
Business logic assembly EasyNetQ code examples:
public class RabbitMessagesReceiverService : BackgroundService
{
readonly IBus _bus;
public RabbitMessagesReceiverService(IBus bus)
{
_bus = bus;
}
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
// receives messages from microservice
_bus.Receive<OutgoingResult>(RabbitHelper.OUTGOING_RESPONSE, async response =>
{
...
}
}
}
or
// sends message to microservice
await _bus.SendAsync<OutgoingRequest>(RabbitHelper.OUTGOING_REQUEST, new OutgoingRequest
{
...
});

How to use shared SignalR Hub from different hosted project in ASP.NET Core 2.2

I'm working with a project built with ASP.NET Core 2.2. The main solution contains multiple projects, which includes API, web and other class libraries.
We've used SignalR to displaying shared messages/notifications between the API project and the web project. For example, adding a new employee record from an API should call SignalR Hub and all the web client should received the notification.
Here is the current structure of our project
|- API
|- Hub_ClassLibrary
|- Services
|- Web
Flow:
Web > services > Hub
API > services > Hub
Hub:
public class NotificationHub : Hub
{
public async Task SendNotification(List<DocumentHistoryModel> notifications)
{
await Clients.All.SendAsync(Constants.ReceiveNotification, notifications);
}
}
Web startup class:
app.UseSignalR(routes =>
{
routes.MapHub<NotificationHub>("/notificationHub");
});
API startup class
app.UseSignalR(routes =>
{
routes.MapHub<NotificationHub>("/notificationHub");
});
Service
private readonly IHubContext<NotificationHub> _hubContext;
public MyService(IHubContext<NotificationHub> hubContext)
{
_hubContext = hubContext;
}
await _hubContext.Clients.All.SendAsync(ReceiveNotification, notifications);
The issue is, I can send and receive notifications from web, but from api call, web doesn't get any notification. I think problem is it creates two separate connections for each project, but then what is the best way to handle this kind of scenario?
Edit: I can get connection id and state "connected" in this api code, however, web is still not receiving any notification. Also tried connection.InvokeAsync
var connection = new HubConnectionBuilder()
.WithUrl("https://localhost:44330/notificationhub")
.Build();
connection.StartAsync().ContinueWith(task =>
{
if (task.IsFaulted)
{
}
else
{
connection.SendAsync("UpdateDashboardCount", "hello world");
}
}).Wait();
For this senario you are better off using pub/sub systems such as rabbitmq, kafka, akka.net, redis. However, if you insist on using signalr, the best solution would be to create a message coordinator with signalr and make it signalr host and then your other services would act as clients that sends their message to that signalr service and receive messages from that (you may even need to implement some logic for making your massage coordinator to queue messages and make them persistant)
Besides, if you can migrate to asp.net core 3 you should definitally checkout grpc bi-directional streaming as well which can be a perfect solution to your problem.
you can inject your HubContext into your controller in API project and try hitting 'InvokeAsync'

How to access hub properties or methods from the outside using hubcontext via DI?

I am using a hubcontext passed via DI in my ASP.Net Core application using a hub helper as described in this post "How can I pass a SignalR hub context to a Hangfire job on ASP .NET Core 2.1?". Basically, I am using a helper that maintains a SignalR hubContext to send messages outside from the hub from the server to connected clients.
Now, I am also trying to keep a list of my connected clients by overriding onConnected method of my SignalR hub as described in this post "How to iterate over users in asp.net core SignalR?", in order to be able to send individual (i.e. specialized) messages.
The problem is that the suggested solution works from the inside of the hub, while when passing the hubContext via DI, I have only access to the hub from the outside.
So for example in my hub helper, I can access _hubContext.Clients but not to _hubContext.Context for example or any of the public methods like onConnected.
Any suggestion?
For my need, I ended up defining GetAllActiveConnections as static in the hub, and using it from the hub helper in conjunction with the injected hubcontext.
My hub contains a static field:
static HashSet<string> CurrentConnections = new HashSet<string>();
and a static public method that uses this field:
public Task GetAllActiveConnections() { ... }
Then my hub helper uses the static method from the hub.
foreach (var activeConnection in MyHub.GetAllActiveConnections())
{
hubcontext.Clients.Client(activeConnection).SendAsync("hi conn : " + activeConnection);
}

Invoke method/Do action before every POST/GET request .NET Core

What I am trying to achieve - My application is simply ASP .Net Core application. It is not Web API. I want to execute method before every post/get request from my app to external sources, for example:
I am sending a post request, to check SSL expiry date to some website API and it returns me a response. According to the response I am sending another request or not. I don't want to place call method statement before every request, I would like to do it globally.
I was trying to achieve this based on http://www.sulhome.com/blog/10/log-asp-net-core-request-and-response-using-middleware
As it occurs, this middleware works(I have it working) only for internal requests(routing requests inside application).
Is there any possibility to do it for all requests?
Thanks in advance
.NET Core allows to create custom middlewares to get into MV pipeline. Here is an example:
public class MyMiddleware
{
private readonly RequestDelegate _next;
public MyMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
//do your checkings
await _next(context);
}
}
In Startup.cs in Config method just regiester it:
app.UseMiddleware<MyMiddleware>(Options.Create(options));
Since you are talking about doing a call on Outgoing requests, you have two mechanisms to solve the problem:
Use an Aspect Oriented Programming Library (like https://www.postsharp.net)
Implement your own Request class (that has the global behavior you desire) and make sure that all requests are done using this class (or a class that inherits from it).
For the second point, a good mechanism is that the base class provides a SendRequest method that receives an HttpRequestMessage and executes the global code. Classes that inherit from it use this method to send the requests and have no access to the underlying HttpClient (so that they cannot run around the SendRequest method).

Categories