Reputation: 722
I have a service made with .Net Core 8, which is a Web API with a SignalR Hub. This service will scale horizontally. For this reason I intend to use the Azure SignalR service in Default mode to act as a proxy between the different instances of my service.
I understand mine is the use case for which Default mode is intended, according to the official documentation https://learn.microsoft.com/en-us/azure/azure-signalr/concept-service-mode.
I have a client developed with ReactJS using the "@microsoft/signalr" library: "^8.0.0"
, which connects to my hubs without any authorization.
Up to this point -without using Azure SignalR- my application is currently running flawlessly (in both cases, containerized and non-containerized in my local environment). For the containerized case I am using Azure Container Application.
If I have done everything right, I have initialized my Azure SignalR instance in Default mode and the only thing I have done is to add the CORS policy for my client (frontend):
On my server (backend) I simply have a hub, called ShopHub in the path /hub/shop
: app.MapHub<ShopHub>("/hub/shop")
.
I have simply implemented the service with .AddAzureSignalR(); and added the connection string provided by Azure SignalR. It seems to be initializing the 5 connections by default, as indicated in the documentation https://learn.microsoft.com/en-us/azure/azure-signalr/signalr-concept-messages-and-connections, so I don't see any problems here:
Now, in my client (frontend) I had to try different things. Initially I replaced my base path, resulting in a path like the following: https://mysignalrservice.service.signalr.net/hub/shop/negotiate?groupId=some-guid&negotiateVersion=1
. And I got a 404. This is the approach that works perfect with my containerized instances, but using Azure SingalR it didn't work. (groupId is the group to which I subscribe the client to, this detail is irrelevant).
Then I found that in some examples after the endpoint provided by Azure SignalR they add /client. This time my route turned out like this: https://mysignalrservice.service.signalr.net/client/hub/shop/negotiate?groupId=some-guid&negotiateVersion=1
, and I got a status 400 with the error 'hub' query parameter is required. Closer, I thought.
Then I added the hub parameter as the error suggested, and my route turned out like this: https://mysignalrservice.service.signalr.net/client/hub/shop/negotiate?hub=shophub&groupId=some-guid&negotiateVersion=1
. This time, again I got a 400.
And as a last alternative to test, I chose to remove the hub path from the URL, resulting in this way: https://mysignalrservice.service.signalr.net/client/negotiate?hub=shophub&groupId=some-guid&negotiateVersion=1
. And this time I got a 401 (Unauthorized). Interesting, evidently the solution may be around here.
One element to consider is that all requests arrived at the Azure SignalR instance, I was able to verify this with the Live trace tool (https://learn.microsoft.com/en-us/azure/azure-signalr/signalr-howto-troubleshoot-live-trace):
I was studying other implementations, unfortunately the vast majority use the Serverless configuration. I understand that in this case it is necessary to add an endpoint for /negotiate (usually employing Azure Functions). I also understand that it is not necessary in the Default mode case, since the negotiation endpoints are already available on my server, and that Azure SignalR should redirect.
As a last idea to test, I also added all the routes in the CQRS configuration of my backend, including those of the Azure SignalR service, also, with no improvement.
Each of the approaches was tested both locally and remotely. Remotely my client is an Azure Static Web App, and as previously mentioned, my server is containerized and mounted on an Azure Container App.
What am I doing wrong?
Thanks in advance!
Regarding the way I connect to SignalR on my client (frontend), I have a function that receives as parameter my shopId
, which is the guid I use to group the customers (I tried to abstract this previously as groupId
in my example, but the livetrace finally shows my implementation details). In baseHubPath
I store the path that leads to my service (just protocol and domain). Then, in .withUrl
I combine my baseHubPath
with the path to the endpoint of my hub /hub/shop
, sending also as parameter shopId
. And this is the whole implementation.
createHubConnection = (shopId: string) => {
const baseHubPath = "https://mysignalrservice.service.signalr.net";
if (!this.hubConnection) {
this.hubConnection = new HubConnectionBuilder()
.withUrl(baseHubPath + '/hub/shop?shopId=' + shopId)
.withAutomaticReconnect()
.configureLogging(LogLevel.Information)
.build();
this.hubConnection.start().catch(error => console.log('Error establishing the connection: ', error));
this.hubConnection.on('ReceiveShopUpdate', (shopUpdated: Shop) => {
this.receiveShopUpdate(shopUpdated);
})
}
}
Upvotes: 1
Views: 301
Reputation: 385
I had the same problems, tried many solutions and wasted a lot of time. So even though I'm a few months late, I thought it might save others time. Finally found the solution here and it is pretty simple. Your client configuration for SignalR should look like this:
this.hubConnection = new signalR.HubConnectionBuilder()
.withUrl('/myhub', {
transport: signalR.HttpTransportType.WebSockets,
})
.configureLogging(signalR.LogLevel.Information)
.build();
Your client has to point to your Web App service url, not to the signalR instance. So it's ok just to use the hub name, e.g. /myHub
.
The original solution mentioned to disable negotiation, but I didn't like as you will not be told about the reason if the connection fails.
Upvotes: 0
Reputation: 22019
If you want to use Azure SignalR Service in your ASP.NET Core application, we need to use Default
Mode.
Before integrating Azure SignalR, we have to make all the features work without using azure signalr.
And HubConnectionBuilder
is used to connect to asp.net core siganlr, not azure signalr service.
So we cannot customize the Url to connect to azure signalr, which is why we can see 404 in Live Trace
.
Wrong Url
https://mysignalrservice.service.signalr.net/hub/shop/negotiate?groupId=some-guid&negotiateVersion=1
And here is the azure signalr workflow you can refer.
Upvotes: 0