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:
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
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();