reactjsasp.net-coreasp.net-core-signalrsignalr.client

Can't establish connection between ASP.NET Core 8 SignalR Hub and React "@microsoft/signalr" client


I wrote an ASP.NET Core 8 backend app containing SignalR Hub

SignalR hub:

namespace SignalRAuthBack
{
    public class MyRequest
    {
        public string? Property1 { get; set; }
    }

    public class DataResponse<T>
    {
        public T? Data { get; set; }
    }

    public interface ISignalRHubСlient
    {
        Task Issue(DataResponse<string> request);
    }

    public class SignalRHub : Hub<ISignalRHubСlient>
    {
        public override Task OnConnectedAsync()
        {
            Console.WriteLine("SignalR Hub Connected");
            return base.OnConnectedAsync();
        }

        public override Task OnDisconnectedAsync(Exception? exception)
        {
            Console.WriteLine("SignalR Hub DisConnected");
            return base.OnDisconnectedAsync(exception);
        }

        public async Task GetIssues(MyRequest request)
        {
            try
            {
                for (int i = 0; i < 10; i++)
                {
                    DataResponse<string> response = new() { Data = $"Datum # {i}" };
                    await Clients.Caller.Issue(response);
                    await Task.Delay(100);
                }
            }
            finally
            {
                Context.Abort();
            }
        }
    }
}

Program.cs:

using SignalRAuthBack;

var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: MyAllowSpecificOrigins,
                      policy =>
                      {
                          policy.WithOrigins("http://localhost:3000");
                          //policy.SetIsOriginAllowed(origin => true); // allow any origin
                          policy.WithMethods("GET", "POST");
                          policy.AllowCredentials();
                      });
});

builder.Services.AddControllers(); 
builder.Services.AddSignalR();

var app = builder.Build();

app.MapControllers();
app.MapHub<SignalRHub>("/SignalRHub");

app.Run();

And my React frontend:

import React, { useState, useEffect } from 'react';
import './App.css';
import * as signalR from '@microsoft/signalr';

function App() {
  const [connection, setConnection] = useState<signalR.HubConnection | null>(null);
  const [messages, setMessages] = useState<string[]>([]);
  const [inputValue, setInputValue] = useState('');

  //---------- USING SignalR CLIENT ----------------------

  useEffect(() => {
    const newConnection = new signalR.HubConnectionBuilder()
      .withUrl('https://localhost:5556/SignalRHub/') 
      .withAutomaticReconnect()
      .build();

    newConnection.start()
      .then(() => {
        console.log('✅ SignalR подключен.');
        setConnection(newConnection);

        newConnection.on('Issue', (response: { data: string }) => {
          setMessages(prev => [...prev, response.data]);
        });
      })
      .catch(err => console.error('❌ Error connecting to SignalR:', err));

    return () => {
      newConnection.stop(); 
    };
  }, []); 
  async function sendMessage(): Promise<void> {
    if (connection && inputValue) {
      try {
        await connection.invoke('GetIssues', { property1: inputValue });
        console.log('📨 Data sent:', inputValue);
      } catch (err) {
        console.error('❌ Data send error:', err);
      }
    }
  }

  return (
    <div style={{ padding: '20px' }}>
      <h1>SignalR Client</h1>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
        placeholder="Введите Property1"
      />
      <button onClick={sendMessage}>Send</button>

      <h2>Server answers:</h2>
      <ul>
        {messages.map((msg, index) => (
          <li key={index}>{msg}</li>
        ))}
      </ul>
    </div>
  );
}

export default App;

When I run the frontend, I get these errors:

Screenshot of the errors

I'm able to create WebSocket connection directly and it works:

function generateWebsocketRequest() {
    return {
      arguments: [{Property1: "Value of Property1"}],
      invocationId: '0',
      target: 'GetIssues',
      type: 1
    };
  };

  const connectWithWebsocket = () => {
    currentWebsocket?.close();
    currentWebsocket = new WebSocket('wss://localhost:5556/SignalRHub/');

    currentWebsocket.onopen = () => {
      currentWebsocket!.send(WSS_HANDSHAKE);
      currentWebsocket!.send(JSON.stringify(generateWebsocketRequest()) + SIGNAL_KEY);
      setCurrentWebsocket(currentWebsocket);
    };

    currentWebsocket.onmessage = (event) => {
      console.log(event.data);
    };

    currentWebsocket.onclose = (event) => {
      console.log("WebSocket closed.")
    };
};

What am I doing wrong with the @microsoft.signalR client?

The full code is on GitHub: https://github.com/EugeniyMaksimov/AspNetCoreAndReactSingnalRConnectionExample


Solution

  • After checking in my side, I found the root cause. You are missing header settings in cors configuration.

    And please also make sure you have enabled the cors middleware by using app.UseCors(MyAllowSpecificOrigins);.

    using mynamespace;
    
    var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
    
    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddCors(options =>
    {
        options.AddPolicy(name: MyAllowSpecificOrigins,
                          policy =>
                          {
                              policy.WithOrigins("http://localhost:3000");
                              //policy.SetIsOriginAllowed(origin => true); // allow any origin
                              policy.WithMethods("GET", "POST");
                              // You are missing  header settings 
                              policy.AllowAnyHeader();  //==> works
                              policy.AllowCredentials();
                          });
    });
    // Add services to the container.
    ...
    builder.Services.AddSignalR();
    
    var app = builder.Build();
    
    ...
    
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    
    app.UseRouting();
    
    // Make sure you have added this line in your project
    app.UseCors(MyAllowSpecificOrigins);
    
    app.UseAuthorization();
    
    app.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
    
    app.MapHub<SignalRHub>("/SignalRHub");
    
    app.Run();