通过 SignalR Core 访问数据库上下文



我正在使用AspNetCore.SignalR,我需要有关如何通过Hub访问SQL Server数据库的建议。关于这一点的资源并不多。我知道如何添加单例,但以后我不知道如何访问它。如何访问在 Hub 任务中启动中使用 Configuration.GetConnectionString 定义的数据库上下文.cs?

谢谢。

以下是相关代码:

启动.cs

public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
DbContextOptionsBuilder<PlayerContext> PlayerContextOptions = new DbContextOptionsBuilder<PlayerContext>();
PlayerContextOptions.UseSqlServer(Configuration.GetConnectionString("Default"));
services.AddSingleton(PlayerContextOptions.Options);
services.AddDbContext<PlayerContext>(options => options.UseSqlServer(Configuration.GetConnectionString("Default")));

services.AddCors(options => options.AddPolicy("CorsPolicy",
builder =>
{
builder.AllowAnyMethod().AllowAnyHeader()
.AllowCredentials();
}));
services.AddSignalR();
} 

但是我根本不知道在我的 Hub 文件中该怎么做。我什至不知道从哪里开始。我添加了单例,但我不知道如何在我的中心文件中访问它。这就是我想做的,但我愿意接受更好的方法:

我的应用.cs

using (PlayerContext dbContext = new PlayerContext(/* Singleton needs to go here */))
{
// do database stuff
} 

使用 SignalR集线器上的依赖项注入来注入 EF DbContext 是一个错误的选择,因为 SignalR 中心本身是一个单一实例,不应依赖于较低的生命周期,因此最终会收到警告。这意味着,您不能向 PerRequest/Transient 生存期范围注册 DbContext,只能使用单一实例。将 DbContext 注册为 Singleton 是一个非常糟糕的选择。创建新上下文的成本并不高,但具有单例上下文的中心将在一段时间后呈指数级增长。

我建议将 DbContextFactory 用于集线器类,在您的集线器中从工厂询问新的 DbContext,并将其放入 using 语句中。您还可以将工厂本身注册为单例,并使集线器构造函数中的依赖关系更加清晰。

using (var dbContextScope = dbContextScopeFactory.Create(options))
{
//do database stuff
dbContextScope.SaveChanges();
}

我用.NET Core 3测试了这段代码!

您必须将 DBContext 添加到 DI,以便可以从中心的构造函数获取它。

public class MyHub
{
private PlayerContext dbContext;

public MyHub(PlayerContext dbContext)
{
this.dbContext = dbContext;
}
public void YourMethod()
{
//call the dbContext here by Dot Notaition
}
}

似乎仍然没有记录访问作用域服务。但是查看源代码,我们可以看到DefaultHubDispatcher每次调用时都会创建范围和中心实例。这意味着我们可以使用DbContext和其他作用域服务,就像我们在asp.net core控制器中一样。

新的DbContext实例在每次调用中心方法时注入到中心构造函数中。调用完成后DbContext将被释放。

启动.cs:

services.AddDbContext<PlayerContext>(
options => { options.UseSqlServer(Configuration.GetConnectionString("Default")); },
ServiceLifetime.Scoped
);

枢纽:

public class PlayerHub
{
private readonly PlayerContext _dbContext;
public PlayerHub(PlayerContext dbContext)
{
_dbContext = dbContext;
}
// using _dbContext 
}

这在带有实体框架核心和 SignalR 的 .net Core 3.1 中对我有用。我不必向启动添加任何内容(实际上在 3.1 中,默认启动中不包含任何连接服务(。一切都在中心和appsettings.json中完成。

应用设置:

{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"ConStr": "Data Source=.\sqlexpress;Initial Catalog=ReactUserTasks;Integrated Security=true;"
}
}

枢纽: 调用在应用设置中设置的"ConStr"连接。

public class MyHub : Hub
{
private string _conn;
public MyHub(IConfiguration configuration)
{
_conn = configuration.GetConnectionString("ConStr");
} 

然后在MyHub设置使用该连接的方法。

public List<Items> GetTasks()
{
var db = new ItemRepository(_conn);
return db.GetTasks();
}