Hallo zusammen,
mal wieder wende ich mich in letzter Verzweiflung an Euch.
Ich habe einen selfhosted signalR Server (.Net CORE 2.2, Konsole App) aufgesetzt:
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.IO;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http.Features;
namespace SignalR_Server
{
class SignalR
{
public static void StartSignalR()
{
var ConsOut = Console.Out;
Console.SetOut(new StreamWriter(Stream.Null));
var host = new WebHostBuilder()
.UseKestrel()
.UseStartup<Startup>()
.UseUrls("http://localhost:5050")
.Build();
try
{
host.Start();
}catch(Exception ex)
{
string err = ex.Message;
}
Console.SetOut(ConsOut);
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options => options.AddPolicy("CorsPolicy", builder =>
{
builder
.AllowAnyMethod()
.AllowAnyHeader().AllowAnyOrigin();
}));
services.AddSignalR();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors("CorsPolicy");
app.UseSignalR(route =>
{
route.MapHub<MyHub>("/stream");
});
}
}
public static class UserHandler
{
public static HashSet<string> ConnectedIds = new HashSet<string>();
}
public class MyHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
Console.WriteLine($"User: {user} says {message}");
}
public Task SendMessageToCaller(string message)
{
return Clients.Caller.SendAsync("ReceiveMessage", message);
}
public Task SendMessageToGroups(string message)
{
List<string> groups = new List<string>() { "SignalR Users" };
return Clients.Groups(groups).SendAsync("ReceiveMessage", message);
}
public override async Task OnConnectedAsync()
{
await Groups.AddToGroupAsync(Context.ConnectionId, "SignalR Users");
UserHandler.ConnectedIds.Add(Context.ConnectionId);
Console.WriteLine($"Connected user: {Context.ConnectionId}");
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception exception)
{
await Groups.RemoveFromGroupAsync(Context.ConnectionId, "SignalR Users");
UserHandler.ConnectedIds.Remove(Context.ConnectionId);
Console.WriteLine($"Disconnected user: {Context.ConnectionId}");
await base.OnDisconnectedAsync(exception);
}
}
}
Der Client ist ein reiner JavaScript Client:
...
<script src="/lib/signalr/dist/browser/signalr.js"></script>
...
const connection = new signalR.HubConnectionBuilder()
.withUrl("http://localhost:5050/stream")
.configureLogging(signalR.LogLevel.Information)
.build();
connection.start().catch(err => console.error(err.toString()));
Rufe ich die HTML Seite mit dem JavaScript auf, meckert der Chrome:
Fehlermeldung:
Access to XMLHttpRequest at 'http://localhost:5050/stream/negotiate' from origin 'https://localhost:44304' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.signalr.js:2430 Error: Failed to complete negotiation with the server: Error
ConsoleLogger.log @ signalr.js:2430
(anonymous) @ signalr.js:2802
step @ signalr.js:2605
(anonymous) @ signalr.js:2586
rejected @ signalr.js:2578
Promise.then (async)
step @ signalr.js:2579
fulfilled @ signalr.js:2577
Promise.then (async)
step @ signalr.js:2579
(anonymous) @ signalr.js:2580
__awaiter @ signalr.js:2576
HttpConnection.getNegotiationResponse @ signalr.js:2773
(anonymous) @ signalr.js:2713
step @ signalr.js:2605
(anonymous) @ signalr.js:2586
step @ signalr.js:2590
(anonymous) @ signalr.js:2586
(anonymous) @ signalr.js:2580
__awaiter @ signalr.js:2576
HttpConnection.startInternal @ signalr.js:2681
HttpConnection.start @ signalr.js:2641
(anonymous) @ signalr.js:1761
step @ signalr.js:1708
(anonymous) @ signalr.js:1689
(anonymous) @ signalr.js:1683
__awaiter @ signalr.js:1679
HubConnection.start @ signalr.js:1750
(anonymous) @ site.js?v=bbSp_ES0ncqX_XK1MVLsTiU7kxXBi9bxmYSw_Kpyug8:11
signalr.js:2430 Error: Failed to start the connection: Error
ConsoleLogger.log @ signalr.js:2430
(anonymous) @ signalr.js:2763
step @ signalr.js:2605
(anonymous) @ signalr.js:2586
rejected @ signalr.js:2578
Promise.then (async)
step @ signalr.js:2579
(anonymous) @ signalr.js:2580
__awaiter @ signalr.js:2576
HttpConnection.startInternal @ signalr.js:2681
HttpConnection.start @ signalr.js:2641
(anonymous) @ signalr.js:1761
step @ signalr.js:1708
(anonymous) @ signalr.js:1689
(anonymous) @ signalr.js:1683
__awaiter @ signalr.js:1679
HubConnection.start @ signalr.js:1750
(anonymous) @ site.js?v=bbSp_ES0ncqX_XK1MVLsTiU7kxXBi9bxmYSw_Kpyug8:11
site.js?v=bbSp_ES0ncqX_XK1MVLsTiU7kxXBi9bxmYSw_Kpyug8:11 Error
(anonymous) @ site.js?v=bbSp_ES0ncqX_XK1MVLsTiU7kxXBi9bxmYSw_Kpyug8:11
Promise.catch (async)
(anonymous) @ site.js?v=bbSp_ES0ncqX_XK1MVLsTiU7kxXBi9bxmYSw_Kpyug8:11
Wie kann ich denn das lösen?
Hi,
steht in der Fehlermeldung mit drin: DU musst Credentials erlauben.
Hallo schuppsl,
Emotionen wie "werd irre" gehören nicht in den Titel. Der Titel sollte eine sachliche Problembeschreibung sein.
probier mal
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddCors(options =>
{
options.AddPolicy("AllowAllOrigins",
builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
// ...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// ...
app.UseCors("AllowAllOrigins");
// ...
}
Aber sei dir bewusst, dass du dann von jeder Domain aus Zugriffe mit allen Headern, Methoden etc. zulässt!
Gruss
Coffeebean
Microsoft MVP // Me // Blog // GitHub // @Egghead // All my talks // Speakerdeck
Also wenn ich es so mache, geht es:
builder
.AllowAnyMethod()
.AllowAnyHeader().AllowCredentials().WithOrigins("https://localhost:44304");
Allerdings muss ich den Port explizit mit angeben bei WithOrigins().
WithOrigins("https://localhost")
Funktioniert nicht, dann kommt die Fehlermeldung:
Fehlermeldung:
Access to XMLHttpRequest at 'http://localhost:5050/stream/negotiate' from origin 'https://localhost:44304' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Das ist korrekt so, der Origin ist eine Kombination aus Protokoll, DNS Name/IP und Port. Deswegen muss alles drei übereinstimmen, sonst kommt diese Fehlermeldung.