We recently built an ASP.NET Core API with Angular, and I'm attempting to implement a basic one-on-one chat functionality using SignalR. We're mapping User IDs to SignalR Connection IDs in a group, and then sending messages directly to users based on their User ID.
It's working fine when tested with an MVC application, but when I try to use SignalR in my Angular project, it's giving me an exception: 'Failed to connect. Error during negotiation request.'
So in this post, we are going to discuss possible reasons for that error and provide solutions for the issue.
The error Angular SignalR "Failed to complete negotiation with the server" typically occurs due to issues with the negotiation between the client (Angular) and the server (SignalR). Let's discess Possible reasons for this:
If you are new to SignalR, you can read about it in this post. Here, I explain SignalR configuration and demonstrate how to use that SignalR hub with a JavaScript client in detail.
1.SignalR Hub Configuration:
Here is example of SignalR Hub Configuration
[AllowAnonymous]
public class ChatHub : Hub
{
public override Task OnDisconnectedAsync(Exception exception)
{
Debug.WriteLine("Client disconnected: " + Context.ConnectionId);
if (OnlineUsers.onlineUsers.Any(a => a.ConnectionId == Context.ConnectionId))
{
OnlineUsers.onlineUsers.RemoveAll(a => a.ConnectionId == Context.ConnectionId);
}
return base.OnDisconnectedAsync(exception);
}
public override Task OnConnectedAsync()
{
Debug.WriteLine("Client connected: " + Context.ConnectionId);
return base.OnConnectedAsync();
}
//create for each user to chat sepearte
public void SetUserChatGroup(string userChatId)
{
var id = Context.ConnectionId;
Debug.WriteLine($"Client {id} added to group " + userChatId);
if (OnlineUsers.onlineUsers == null)
OnlineUsers.onlineUsers = new List<OnlineUserModel>();
if (!OnlineUsers.onlineUsers.Any(a => a.ConnectionId == Context.ConnectionId))
{
OnlineUsers.onlineUsers.Add(new OnlineUserModel { ConnectionId = Context.ConnectionId, ChatId = userChatId });
}
Groups.AddToGroupAsync(Context.ConnectionId, userChatId);
}
//send message to user
public async Task SendMessageToGroup(string senderChatId, string receiverChatId, string message)
{
var chatHistory = await new DbChatHistoryLog().InsertChatHistory(new ChatModel { SenderId = senderChatId, ReciverId = receiverChatId, Message = message });
if (chatHistory != null && chatHistory.ChatId > 0 && Clients!=null)
{
await Clients.Group(receiverChatId).SendAsync("ReceiveMessage", chatHistory.SenderId, chatHistory.SenderName, chatHistory.ReciverId, chatHistory.Message);
}
}
}
2.CORS (Cross-Origin Resource Sharing) Configuration:
app.UseCors(builder => builder
.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed((host) => true)
.AllowCredentials()
);
Program.cs configuration example:
using SignalRDemo.Chat;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddSignalR();
builder.Services.AddSingleton<ChatingHub>();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
//Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseCors(builder => builder
.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed((host) => true)
.AllowCredentials()
);
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.MapHub<ChatingHub>("/ChatingHub");
app.Run();
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddOpenApiDocument(c =>
{
c.Title = "SignalR API";
});
services.AddCors(o => o.AddPolicy("AllowOrigin", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSignalR();
services.AddSingleton<ChatingHub>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseStaticFiles(); // For the wwwroot folder
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseCors(builder => builder
.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed((host) => true)
.AllowCredentials()
);
app.UseHttpsRedirection();
// Make sure you call this before calling app.UseMvc()
app.UseSignalR(routes =>
{
routes.MapHub<ChatingHub>("/ChatingHub");
});
app.UseMvc();
//Register the Swagger generator
app.UseOpenApi();
app.UseSwaggerUi3();
}
}
3.Authentication and Authorization:
4.Firewall or Network Restrictions:
5.Check Version :
6.Make sure using correct Hub Url and try with skipNegotiation=true
onnection = new signalR.HubConnectionBuilder()
.configureLogging(signalR.LogLevel.Debug)
.withUrl("http://localhost:4587/ChatHub", {
skipNegotiation: true,
transport: signalR.HttpTransportType.WebSockets
})
.build();
By following these solutions you should be able to resolve the "Failed to complete negotiation with the server" error in your Angular/SignalR application
Read Similar Articles
- Solved Error: Only authentication clear text password and authentication md5 password supported for now. received 10
- Solved : Error starting applicationcontext. to display the condition evaluation report re-run your application with 'debug' enabled
- [Solved]-LEFT OUTER JOIN in LINQ With Where clause in C#
- How To Edit/Delete Selected Row From HTML Table Using JavaScript
- How to use Merge Statement in the SQL Server
- What smart contract function is not used in honeypot tokens?
- Sample image upload rest api for testing