Reputation: 521
Using SignalR for my server and Angular for my client... When I run my client I receive these errors:
zone.js:2969 OPTIONS https://localhost:27967/chat/negotiate 0 ()
Utils.js:148 Error: Failed to complete negotiation with the server: Error
Utils.js:148 Error: Failed to start the connection: Error
I am guessing it is something with CORS... I am trying to implement a simple chat application. I am using the latest verison of SignalR:
Here is the github that contains the code for the tutorial I am following. SignalR Chat Tutorial
Here is my startup
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
namespace signalrChat
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(o => o.AddPolicy("CorsPolicy", builder =>
{
builder
.AllowAnyMethod()
.AllowAnyHeader()
.WithOrigins("http://localhost:4200");
}));
services.AddSignalR();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors("CorsPolicy");
app.UseSignalR(routes =>
{
routes.MapHub<ChatHub>("/chat");
});
}
}
}
And here is my client:
import { Component, OnInit } from '@angular/core';
import { HubConnection, HubConnectionBuilder } from '@aspnet/signalr';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
private hubConnection: HubConnection;
nick = '';
message = '';
messages: string[] = [];
ngOnInit() {
this.nick = window.prompt('Your name:', 'John');
this.hubConnection = new HubConnectionBuilder().withUrl('https://localhost:27967/chat').build();
this.hubConnection
.start()
.then(() => console.log("Connection Started!"))
.catch(err => console.log("Error while establishing a connection :( "));
this.hubConnection.on('sendToAll', (nick: string, receiveMessage: string) => {
const text = `${nick}: ${receiveMessage}`;
this.messages.push(text);
})
}
public sendMessage(): void {
this.hubConnection
.invoke('sendToAll', this.nick, this.message)
.catch(err => console.log(err));
}
}
I assume it may be something with cors. Thank you!
EDIT: I just recreated the signalr implementation in visual studio and it worked. I believe I chose the wrong settings on start up.
Upvotes: 45
Views: 103511
Reputation: 739
connection = new signalR.HubConnectionBuilder()
.configureLogging(signalR.LogLevel.Debug) // add this for diagnostic clues
.withUrl("http://localhost:5000/decisionHub", {
skipNegotiation: true, // skipNegotiation as we specify WebSockets
transport: signalR.HttpTransportType.WebSockets // force WebSocket transport
})
.build();
Upvotes: 73
Reputation: 333
I had the same error due to cross origin. This solved it for me program.cs (dotnet 6) or startup.cs (dotnetcore < 6)
app.UseCors(builder => builder
.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed(_ => true)
.AllowCredentials()
);
Notice that you should not open all origins if it is not a development environment or special cases.
Upvotes: 0
Reputation: 4664
I was pointing to the wrong endpoint. I was using
https://localhost:5001/api/message-hub
instead of
https://localhost:5001/message-hub
(extra /api)
Also if you're using Angular, you're likely to get a Websocket not OPEN error right after fixing this one, so here's a link to save you from more searches.
Upvotes: 7
Reputation: 1957
In my case it wasn't necessary all those stuff, I was missing the https instead http, and it worked like a charm.
const connection = new signalR.HubConnectionBuilder()
.configureLogging(signalR.LogLevel.Debug)
.withUrl('https://localhost:44308/message')
.build();
Upvotes: 3
Reputation: 360
I had the same problem, and it turns out that the launchSettings.json in the part where it says signalRchatServer does nothing, the url that worked with me was that of the iisexpress, I say it because there are many places where they say that the url is the one below .
Upvotes: 7
Reputation: 780
I waste almost two days for this and finally figured out,
When this error occurs?
Why this error occurs?
The error occurs because new SignalR does not allow you to use old server & new client or new server & old client
It means if you create the SignalR server using .Net core then you must create the client using .Net Core
This was the issue in my case.
Upvotes: 2
Reputation: 2590
I faced the slimier issue and I fixed it by adding
skipNegotiation: true,
transport: signalR.HttpTransportType.WebSockets
in client-side as @Caims mentioned. But I don't think this is the correct solution and feel more like a hack 😊.
What you have to do is adding AllowCredentials
in server side. Anyway when it's coming to Azure you can't relay on that fix. So no need enable WSS only in client side.
Here is my ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(o => o.AddPolicy("CorsPolicy", builder => {
builder
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.WithOrigins("http://localhost:4200");
}));
services.AddSignalR();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
This is my Configure method:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors("CorsPolicy");
app.UseSignalR(routes =>
{
routes.MapHub<NotifyHub>("/notify");
});
app.UseMvc();
}
And finally this is how I connected from client-side:
const connection = new signalR.HubConnectionBuilder()
.configureLogging(signalR.LogLevel.Debug)
.withUrl("http://localhost:5000/notify", {
//skipNegotiation: true,
//transport: signalR.HttpTransportType.WebSockets
}).build();
connection.start().then(function () {
console.log('Connected!');
}).catch(function (err) {
return console.error(err.toString());
});
connection.on("BroadcastMessage", (type: string, payload: string) => {
this.msgs.push({ severity: type, summary: payload });
});
Upvotes: 28
Reputation: 21719
I was facing the same problem in my Angular application when I try to connect to Azure SignalR service Azure Function.
[FunctionName("Negotiate")]
public static IActionResult Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, [SignalRConnectionInfo(HubName = "broadcast")] SignalRConnectionInfo info,
ILogger log) {
log.LogInformation("Negotiate trigger function processed a request.");
return info != null ? (ActionResult) new OkObjectResult(info) : new NotFoundObjectResult("SignalR could not load");
}
And below was my init() function code in Angular service.
init() {
this.getSignalRConnection().subscribe((con: any) => {
const options = {
accessTokenFactory: () => con.accessKey
};
this.hubConnection = new SignalR.HubConnectionBuilder()
.withUrl(con.url, options)
.configureLogging(SignalR.LogLevel.Information)
.build();
this.hubConnection.start().catch(error => console.error(error));
this.hubConnection.on('newData', data => {
this.mxChipData.next(data);
});
});
}
My problem was with the con.accessKey
. I just checked the properties of the SignalRConnectionInfo
class and understood that I need to use accessToken
instead of accessKey
.
public class SignalRConnectionInfo {
public SignalRConnectionInfo();
[JsonProperty("url")]
public string Url {
get;
set;
}
[JsonProperty("accessToken")]
public string AccessToken {
get;
set;
}
}
So after changing the code to accessTokenFactory: () => con.accessToken
everything worked as usual.
Upvotes: 3