Beginner in SignalR here, I recently experimented with implementing a private chat in SignalR and it worked fine. However, I'm having trouble implementing it in a full scale patient management system. I would like to know what steps are typically involved in a successful hub connection ? My understanding is that the initial step is a negotiation step used to retrieve a connection Token . In the second step this connection Token is used to create a web socket connection to the Hub. However , my network tab looks like this and I'm not sure what's happening here. Are these tries to reconnect? is the connection established in the first three steps?
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
namespace Main.Hubs
{
[Authorize]
public class ChatHub : Hub
{
public override Task OnConnectedAsync()
{
var header_token = Context.GetHttpContext().Request.Headers["Authorization"].FirstOrDefault();
var token = header_token.Substring("Bearer ".Length);
var handler = new JwtSecurityTokenHandler();
var securitytoken = handler.ReadJwtToken(token);
var Username = securitytoken.Claims.First(claim => claim.Type == "Username").Value.ToString();
Groups.AddToGroupAsync(Context.ConnectionId, Username);
return base.OnConnectedAsync();
}
public async Task SendMessageToGroup(string sender, string receiver, string message)
{
await Clients.Group(receiver).SendAsync("ReceiveMessage", sender, message);
}
public async Task SendMessage(string user, string message)
{
await Clients.Others.SendAsync("ReceiveMessage", user, message);
}
}
}
Im just trying to connect the user but it seems as if the connection is'nt established because i'm not being able to pass any messages using the other functions .The Program.cs and Javascript file look like:
using MyApp.Repository;
using Microsoft.AspNetCore.Builder;
using MyApp.Repositorys;
using MyApps.Repository;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using Main.EmailService.Models;
using Main.EmailService;
using Microsoft.Extensions.Configuration;
using DataAccess.MiddleWare;
using DataAccess.Repository;
using Main;
using Main.Hubs;
using Microsoft.AspNetCore.Http.Connections;
//using JWTExample;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
//builder.Services.AddControllers();
builder.Services.AddControllers()
.AddJsonOptions(o => o.JsonSerializerOptions
.ReferenceHandler = ReferenceHandler.IgnoreCycles);
builder.Services.AddCors();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
//builder.Services.AddSwaggerGen();
builder.Services.AddSwaggerGen(c =>
{
// Add the "Bearer" scheme to the security definitions
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer"
});
// Enable authorization using the "Bearer" scheme
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] { }
}
});
// Other Swagger configurations...
});
var emailConfig = builder.Configuration
.GetSection("EmailConfiguration")
.Get<EmailConfiguration>();
builder.Services.AddSingleton(emailConfig);
builder.Services.AddScoped<IEmailService, EmailService>();
builder.Services.AddSingleton<TokenBlacklistService, TokenBlacklistService>();
//builder.Services.AddSwaggerGen(c =>
//{
// c.SwaggerDoc("v1", new OpenApiInfo { Title = "MyApp", Version = "v1" });
//});
//Dependency Injection for EDI Repository
builder.Services.AddScoped<IDALRepository, DALRepository>();
builder.Services.AddScoped<IDataImport, DALRepository>();
builder.Services.AddScoped<PaymentIDALRepository, PaymentDALRepository>();
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o =>
{
o.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey
(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])),
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = false,
ValidateIssuerSigningKey = true
};
});
builder.Services.AddAuthorization();
builder.Services.AddSignalR();
var app = builder.Build();
//Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment() || app.Environment.IsProduction())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI();
//app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyApp v1"));
}
app.UseHttpsRedirection();
app.UseMiddleware<LoggingMiddleware>();
app.UseRouting();
//app.UseCors(options =>
//{
// options.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
//});
app.UseCors(x => x
.AllowAnyMethod()
.AllowAnyHeader()
.SetIsOriginAllowed(origin => true)
.AllowCredentials());
app.UseAuthentication();
app.UseAuthorization();
//app.UseMiddleware<TokenBlacklistMiddleware>();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
//app.MapControllers();
app.MapHub<ChatHub>("/chatHub");
app.Run();
import { useEffect, useState } from 'react';
import { HttpTransportType, HubConnectionBuilder } from '@microsoft/signalr';
import store from '../../store';
const useSignalR = (hubUrl) => {
const [connection, setConnection] = useState(null);
let token = store.getState();
token = token.Login.token
useEffect(() => {
const newConnection = new HubConnectionBuilder()
.withUrl(hubUrl, {
// skipNegotiation: true, // Skip negotiation
// transport: HttpTransportType.WebSockets, // Specify transport type directly
accessTokenFactory: () => token // Provide access token
})
// .withAutomaticReconnect()
.build();
setConnection(newConnection);
}, [hubUrl]);
useEffect(() => {
console.log('connection', connection);
if (connection) {
console.log('connection', connection);
connection.start()
.then(() => console.log("SignalR Connected"))
.catch(err => console.error("SignalR Connection Error: ", err));
return () => {
connection.stop();
};
}
}, [connection]);
return connection;
};
export default useSignalR;