gpt4 book ai didi

.net-core - 向特定用户发送 SignalR 消息

转载 作者:行者123 更新时间:2023-12-03 08:05:53 25 4
gpt4 key购买 nike

我有一个 Blazor wasm 应用程序,它使用 SignalR 向客户端发送消息。当向所有客户端发送消息时,一切正常。为了向特定客户端发送消息,我想为每个客户端创建一个组:

public override async Task OnConnectedAsync()
{
//enter code here to keep track of connected clients
var userName = Context.User.FindFirst(ClaimTypes.NameIdentifier); // get the username of the connected user

await Groups.AddToGroupAsync(Context.ConnectionId, $"user_{userName}");

await base.OnConnectedAsync();
}

因此,在 Groups.AddToGroupAsync 中,我想添加 ConnectionId 和 userName。但是,创建连接时 userName 始终为 null。我应该如何在这里获得唯一的用户名?我的所有用户都是使用 .NET Core Identity 和 IdnetityServer 注册的。我还尝试了此方法的 [Authorize] 属性,但 userName 仍然为 null。

如果我在集线器类上使用 [Authorize] 属性,则从客户端连接到集线器时会收到 UnAuthorized 401 错误:

hubConnection = new HubConnectionBuilder()
.WithUrl(NavigationManager.ToAbsoluteUri("/broadcaster"))
.Build();
...
await hubConnection.StartAsync(); //returns 401 error

这是startup.cs:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using PakPx1.Server.Data;
using PakPx1.Server.Models;
using System;
using Syncfusion.Blazor;
using System.Linq;
using System.Threading.Tasks;
using PakPx1.Server.Hubs;
using PakPx1.Shared.Models;
using PakPx1.Client;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using PakPx1.Server.Utils;
using Microsoft.AspNetCore.SignalR;

namespace PakPx1.Server
{
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.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
//services.AddDbContext<ApplicationDbContext>(options =>
// options.UseSqlServer(
// Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddSyncfusionBlazor();
services.AddDbContext<ApplicationDbContext>(options =>
options.UseMySql(Configuration.GetConnectionString("DefaultConnection"), new MySqlServerVersion(new Version(5, 6, 48))));
services.AddOptions();
services.AddControllers();

services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();


services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
options.IdentityResources["openid"].UserClaims.Add("role");
options.ApiResources.Single().UserClaims.Add("role");

});


services.AddAuthentication()
.AddIdentityServerJwt();

services.AddHttpContextAccessor();
services.AddAuthorization();

//services.AddSingleton<IUserIdProvider, NameUserIdProvider>();

services.AddControllersWithViews();
services.AddRazorPages();
services.AddResponseCompression(opts =>
{
opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
new[] { "application/octet-stream" });
});
services.Configure<IdentityOptions>(options =>
{
// Password settings
options.Password.RequireDigit = false;
options.Password.RequiredLength = 4;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequireLowercase = false;

});
services.AddServerSideBlazor();
services.AddResponseCompression(opts =>
{
opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(
new[] { "application/octet-stream" });
});
services.AddMvc().AddMvcOptions(options =>
{
options.EnableEndpointRouting = false;
});
services.AddMvcCore(options => options.OutputFormatters.Add(new XmlSerializerOutputFormatter()));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services.AddMvc().AddXmlDataContractSerializerFormatters();
services.AddSignalR();


//services.AddCors(options =>
//{
// options.AddPolicy("EnableCORS", builder =>
// {
// builder.AllowAnyOrigin().AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().AllowCredentials().Build();
// });
//});
//services.AddMvc(option => option.EnableEndpointRouting = false).SetCompatibilityVersion(CompatibilityVersion.Version_3_0);


}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)
{
app.UseResponseCompression();

if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}

app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();

app.UseRouting();

app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapHub<Broadcaster>("/broadcaster");
endpoints.MapFallbackToFile("index.html");
});
CreateRoles(serviceProvider).Wait();

}

private async Task CreateRoles(IServiceProvider serviceProvider)
{
var RoleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();

string[] roleNames = { "Admin", "Business Manager", "Client", "Settlement Manager", "VOTClient" };
IdentityResult roleResult;

foreach (var roleName in roleNames)
{
var roleExist = await RoleManager.RoleExistsAsync(roleName);
if (!roleExist)
{
roleResult = await RoleManager.CreateAsync(new IdentityRole(roleName));
}
}

}




}
}

最佳答案

您的简单答案将发送给具有 id 的特定用户:

Clients.Client(connectionId).SendAsync

但首先你需要保存所有连接ID,并在用户断开连接时删除ID。在您的集线器 Controller 中覆盖这些方法:

public static HashSet<UserInfoDto> Users = new HashSet<UserInfoDto>();

public override Task OnConnectedAsync()
{
Users.Add(new UserInfoDto() { ConnectionId = Context.ConnectionId });
return base.OnConnectedAsync();
}

public override async Task OnDisconnectedAsync(Exception exception)
{
var usr = Users.First(x => x.ConnectionId == Context.ConnectionId);
Users.Remove(usr);

if (!string.IsNullOrEmpty(usr.Name))
{
await UserContactListUpdate();
}
await base.OnDisconnectedAsync(exception);
}

接下来您需要在登录、启动或其他状态后存储附加数据,例如我们需要在用户提交信息后添加登录信息,我们更新该用户的信息:

public async Task Login(string connectionId, string name, string imageId)
{
var user = Users.First(x => x.ConnectionId == connectionId);

if (string.IsNullOrEmpty(imageId))
{
var path = Path.Combine(environment.ContentRootPath, "wwwroot", "images");
var files = Directory.GetFiles(path, "*.png");
var rnd = new Random();
var index = rnd.Next(1, files.Length);

imageId = Path.GetFileNameWithoutExtension(files[index]);
}

user.Name = name;
user.ImageUrl = imageId;
await Clients.Client(connectionId).SendAsync("LoginSucess", user);
await UserContactListUpdate();
}

我在 https://github.com/mahdiit/ChatServer 中编写了一个示例聊天服务器应用程序

关于.net-core - 向特定用户发送 SignalR 消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72336726/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com