Search code examples
reactjsasp.net-corereact-hookssignalrasp.net-core-signalr

React .NET - Using singalR to get a number of all active connection


I am trying to get a signalR connection with my react app, I have created the hub in asp .net core, but it wont seem to work in my frontend.

I am new when it comes to signalR, but I have created this before, with an asp .net core MVC application, so I know the logic works.

But I have never done anything with signalR using React. So thats why I could need some help.

Let me show you some code SignalR Hub

public class OnConnectionHub : Hub
    {
        public static int ConnectionCount { get; set; }

        public override Task OnConnectedAsync()
        {
            ConnectionCount++;
            Clients.All.SendAsync("updateConnectionCount", ConnectionCount).GetAwaiter().GetResult();
            return base.OnConnectedAsync();
        }

        public override Task OnDisconnectedAsync(Exception? exception)
        {
            ConnectionCount--;
            Clients.All.SendAsync("updateConnectionCount", ConnectionCount).GetAwaiter().GetResult();
            return base.OnDisconnectedAsync(exception);
        }
    }

Fairly simple, just increment and decrement on the OnConnectedAsync and OnDisconnectedAsync

This the hub url I created

endpoints.MapHub<OnConnectionHub>("hubs/onConnectionHub");

And here is some code in my react component

import { HubConnectionBuilder } from "@microsoft/signalr"
import { useState } from "react"

export const ConnectionCount = () => {
    const [connectionCount, setConnectionCount] = useState(0)
    // create connection
    const connection = new HubConnectionBuilder()
        .withUrl("https://localhost:7199/hubs/onConnectionHub")
        .build()

    // connect to method that hub invokes
    connection.on("updateConnectionCount", (onConnection) => {
        setConnectionCount(onConnection)
        }
    )

    // start connection
    connection.start();

    return <p>Active members {connectionCount}</p>
}

The errors I get

react_devtools_backend.js:4026 [2022-07-14T08:31:46.444Z] Error: Failed to complete negotiation with the server: TypeError: Failed to fetch
client.onmessage @ WebSocketClient.js:50
2HttpConnection.ts:350 Uncaught (in promise) Error: Failed to complete negotiation with the server: TypeError: Failed to fetch
    at HttpConnection._getNegotiationResponse (HttpConnection.ts:350:1)
    at async HttpConnection._startInternal (HttpConnection.ts:247:1)
    at async HttpConnection.start (HttpConnection.ts:138:1)
    at async HubConnection._startInternal (HubConnection.ts:206:1)
    at async HubConnection._startWithStateTransitions (HubConnection.ts:180:1)

Thanks!


Solution

  • Solved it by updating the corspolicy a bit like this

    builder.Services.AddCors(options =>
    {
        var frontendUrl = builder.Configuration.GetValue<string>("frontend_url");
        options.AddPolicy("allowConnection", builder =>
        {
            builder.WithOrigins(frontendUrl)
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials()
                .WithExposedHeaders(new string[] { "totalAmountOfRecords" });
        });
    });
    

    Creating a policy instead of default policy And

    app.UseCors("allowConnection");
    

    Also, in the frontend

    import { HubConnectionBuilder } from "@microsoft/signalr"
    import { useEffect, useState } from "react"
    
    export const ConnectionCount = () => {
        const [connectionCount, setConnectionCount] = useState(0)
        // create connection
        useEffect(() => {
            const connection = new HubConnectionBuilder()
            .withUrl("https://localhost:7199/hubs/onConnectionHub")
            .build()
    
        // connect to method that hub invokes
        connection.on("updateConnectionCount", (onConnection) => {
            setConnectionCount(onConnection)
            }
        )
    
        // start connection
        connection.start().then(() => {
            console.log("Connection started")
        });
        }, [])
        
    
        return(
            <section>
                <p>Active connections: {connectionCount}</p>
            </section>
        )
    }