Angular/SignalR Error: Failed to complete negotiation with the server
Asked Answered
P

8

44

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.

Paronym answered 29/8, 2018 at 21:14 Comment(6)
Did you try without "localhost:4200" in .WithOrigins("localhost:4200");Succinic
Yes, doing withOrigins(); does not change anything.Paronym
I made a repository with a starter version working : github.com/WillieFitzPatrick/ng6-signalR.gitSuccinic
Can you please check proxy server settings, set internet option connection tab Lan settings -> Select automatically detect settings and uncheck proxy configuration.Till
@Paronym What did you mean by 'I just recreated the signalr implementation' ? Please provide details. It may be usefull, I have the same issue. Did you create a solution from scratch or did you rewrite only client/server-side code? Or maybe you reinstalled/updated some of packages/libraries (which ones) etc?Ange
This a little late, but make sure you have the correct url http vs https was my issueGymnastic
M
71
connection = new signalR.HubConnectionBuilder()
    .configureLogging(signalR.LogLevel.Debug)
    .withUrl("http://localhost:5000/decisionHub", {
      skipNegotiation: true,
      transport: signalR.HttpTransportType.WebSockets
    })
    .build();
Mut answered 21/10, 2018 at 8:44 Comment(3)
Please give us an explanation on how this solves OP issue.Zigmund
An explanation is giving here: learn.microsoft.com/en-us/javascript/api/%40aspnet/signalr/… "A boolean indicating if negotiation should be skipped. Negotiation can only be skipped when the transport property is set to 'HttpTransportType.WebSockets'. That is why @Claims set the transport type to websockets. One drawback of this I believe is that this will not work in older browsers that do not support websocketsNadenenader
Thanks, they was to include options.SkipNegotiation = true; for DEBUG using localhost, on release it was okayAnxious
D
28

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 });
});
Dorcy answered 26/5, 2019 at 18:10 Comment(4)
AllowCredentials (using app.UseCors(options => options.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().AllowCredentials()); on Startup.cs configure method)worked for me!Malan
hmm - I cannot get this working If I try with skip and websocket then I get a 307 error (redirect) and without skip I get the CORS error.Earmuff
found the problem, I had app.UseHttpsRedirection(), and it redirected to https://...5001. Once I disabled this it workedEarmuff
I can confirm that adding AllowCredentials() fixed the problem.Chaworth
O
7

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 .

enter image description here

Optician answered 26/8, 2019 at 8:40 Comment(0)
A
7

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.

Autotruck answered 26/7, 2021 at 17:11 Comment(0)
A
2

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.

Auschwitz answered 27/12, 2018 at 10:0 Comment(0)
M
2

I waste almost two days for this and finally figured out,

When this error occurs?

  • When you upgrade your existing SignalR server project to .Net Core but do not upgrade the client
  • When you create the SignalR server using .Net core but you use traditional .Net framework for the client

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.

Mountainside answered 15/8, 2019 at 19:33 Comment(0)
U
2

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();
Uwton answered 21/10, 2019 at 23:23 Comment(0)
E
-1

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.

Emilie answered 28/11, 2021 at 13:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.