我使用 SignalR 作为实时技术,使用 .NET 6.0 完成了通知服务。我需要将此后端上传到 Windows Server,以便我可以尝试该项目,但是,当我上传时,我遇到了一些错误。
我已在 IIS 上启用 Web 套接字
这是我的 web.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<location path="." inheritInChildApplications="false">
<system.webServer>
<handlers>
<add name="aspNetCore" path="/Connect" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet" arguments=".\NotificationService.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" />
</system.webServer>
</location>
</configuration>
如您所见,我已将 SignalR Hub 的路径(/Connect)添加到 web.config 中。 我已经安装了 SDK,并且还从服务器管理器启用了 Web 套接字功能。
我将在下面与您分享后端的代码:
这是我的程序.cs:
//JWT Bearer
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(o =>
{
o.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("siudhg987IJHASDhaisd7ASDihasdjkqUIHasd123098345ASOIDU"))
};
o.TokenValidationParameters = new TokenValidationParameters
{
IssuerSigningKey = new SymmetricSecurityKey
(Encoding.UTF8.GetBytes(builder.Configuration["secreatKey"])),
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = false,
ValidateIssuerSigningKey = true
};
o.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
// If the request is for our hub...
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) &&
(path.StartsWithSegments("/Connect"))) // Change "/Connect" to your hub route
{
// Read the token from the query string
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
});
//Rabbit
builder.Services.AddScoped<IRabbitConnection, RabbitConnection>();
//SignalR
builder.Services.AddSignalR();
builder.Services.AddSignalR(opt => { opt.HandshakeTimeout = TimeSpan.MaxValue; });
builder.Services.AddSingleton<INotificationServiceRepository, NotificationServiceRepository>();
builder.Services.AddSingleton<IUserConnectionManager, UserConnectionManager>();
builder.Services.AddSingleton<INotificationStore,MemoryNotificationStore>();
builder.Services.AddSingleton<NotificationMemoryStorage>();
builder.Services.AddScoped<INotificationServiceRepository, NotificationServiceRepository>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseCors();
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseWebSockets(); ;
//Ruta para conectarse al servidor de ws
app.MapHub<NotificationHub>("/Connect");
app.UseAuthorization();
app.MapControllers();
app.Run();
这是我的中心:
public class NotificationHub : Hub<INotificationHub>
{
private readonly IUserConnectionManager _userConnectionManager;
private readonly INotificationStore _notificationStore;
public NotificationHub(IUserConnectionManager userConnectionManager, INotificationStore notificationStore)
{
_userConnectionManager = userConnectionManager;
_notificationStore = notificationStore;
}
//<------------------------------------------------------------------------------->
public override async Task OnConnectedAsync()
{
var token = Context.GetHttpContext().Request.Headers["access_token"];
if (!string.IsNullOrEmpty(token))
{
var result = await UserConnectionAsync(token);
await Clients.Client(Context.ConnectionId).ConnectionResponse(result.response);
if (result.succesfulConnection)
{
await SendStoredNotifications(result.userId);
}
else
{
var response = new ServerResponse
{
status = "Rejected",
message = "Error en la autorizacion"
};
await Clients.Client(Context.ConnectionId).ConnectionResponse(response);
Context.Abort();
}
}
else
{
var response = new ServerResponse
{
status = "Rejected",
message = "Token no proporcionado"
};
await Clients.Client(Context.ConnectionId).ConnectionResponse(response);
Context.Abort();
}
}
//<------------------------------------------------------------------------------->
private async Task<(bool succesfulConnection, ServerResponse response, string userId)> UserConnectionAsync(string token)
{
var handler = new JwtSecurityTokenHandler();
var jsonToken = handler.ReadToken(token) as JwtSecurityToken;
if (jsonToken != null)
{
string userId = jsonToken.Claims.FirstOrDefault(claim => claim.Type == "email" || claim.Type == "uid")?.Value;
var response = new ServerResponse();
if (!string.IsNullOrEmpty(userId))
{
await GetConnectionId(userId);
response.status = "Accepted";
response.message = "Conexion Exitosa";
return (true, response, userId);
}
else
{
response.status = "Rejected";
response.message = "Error en la autorizacion";
return (false, response, null);
}
}
else
{
var response = new ServerResponse
{
status = "Rejected",
message = "Error en la autorizacion"
};
return (false, response, null);
}
}
//<------------------------------------------------------------------------------->
private async Task SendStoredNotifications(string userId)
{
if (!string.IsNullOrEmpty(userId))
{
var notifications = _notificationStore.RetrieveNotifications(userId);
foreach (var notification in notifications)
{
await Clients.Client(Context.ConnectionId).SendNotification(notification);
}
_notificationStore.ClearNotifications(userId);
}
}
//<------------------------------------------------------------------------------->
public async Task<string> GetConnectionId(string userId)
{
_userConnectionManager.KeppUserConnection(userId, Context.ConnectionId);
return Context.ConnectionId;
}
//<------------------------------------------------------------------------------->
public override async Task OnDisconnectedAsync(Exception? exception)
{
var connectionId = Context.ConnectionId;
_userConnectionManager.RemoveUserConnection(connectionId);
await base.OnDisconnectedAsync(exception);
}
//<------------------------------------------------------------------------------->
public async Task MessageCheck(NotificationRequestModel request)
{
//meter validaciones
switch (request.Target.Device)
{
case "Admin":
if (request.Target.User.Contains("*"))
{
SendNotificationToAllUsers(request.Notification);
}
else
{
SendNotificationToSpecificUser(request.Notification, request.Target.User);
}
break;
}
}
//<------------------------------------------------------------------------------------->
public async Task SendNotificationToAllUsers(NotificationModel message)
{
var allUserIds = _userConnectionManager.GetAllUserIds();
foreach (var userId in allUserIds)
{
var connectionsIds = _userConnectionManager.GetUserConnections(userId);
if (connectionsIds.Any())
{
foreach (var connectionId in connectionsIds)
{
await Clients.Client(connectionId).SendNotification(message);
}
}
else
{
_notificationStore.StoreNotification(userId, message);
}
}
}
//<------------------------------------------------------------------------------->
public async Task SendNotificationToSpecificUser(NotificationModel message, List<string> target)
{
foreach (var userId in target)
{
var connectionIds = _userConnectionManager.GetUserConnections(userId);
if (connectionIds.Count() > 0)
{
foreach (var connectionId in connectionIds)
{
await Clients.Client(connectionId).SendNotification(message);
}
}
else
{
_notificationStore.StoreNotification(userId, message);
}
}
}
//<------------------------------------------------------------------------------->
}
我对代码表示歉意。
在我的 launchsettings.json 中,我激活了 IIS Express:
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
我也尝试通过邮递员连接: HTTP:
WS:
请不要使用
/Connect
。
app.MapHub<NotificationHub>("/Connect");
我们可以使用其他词语,如
MainHub
、Test1
等等。
app.MapHub<NotificationHub>("/MainHub");
app.MapHub<NotificationHub>("/Test1");