c# - 使用 .AddDbContext() 和依赖注入时,Discord.NET 机器人在所有模块之间共享相同的 DatabaseContext
问题描述
我正在创建一个 Discord Bot,它应该在行DatabaseContext
会成员发出命令时创建和处理一个。DatabaseContext
问题是模块之间共享相同的内容。我已经在使用.AddDbContext()
od.AddDbContextPool()
所以我不理解这种行为。
我正在使用 Discord.NET、EFCore 和依赖注入。
这是我的 Program.cs 文件:
class Program
{
private const string _token = "token";
private readonly DiscordSocketClient _client;
private readonly CommandService _commands;
private readonly IServiceProvider _services;
public static void Main(string[] args)
=> new Program().MainAsync().GetAwaiter().GetResult();
private Program()
{
_client = new DiscordSocketClient();
_commands = new CommandService();
_client.Log += Log;
_commands.Log += Log;
_services = ConfigureServices();
}
private IServiceProvider ConfigureServices()
{
var map = new ServiceCollection()
.AddSingleton(_client)
.AddSingleton(_commands)
.AddDbContext<DatabaseContext>(options =>
options.UseMySql(SharedConfiguration.connectionString,
new MySqlServerVersion(new Version(5, 7))));
return map.BuildServiceProvider();
}
private Task Log(LogMessage msg)
{
Console.WriteLine($"[{DateTime.UtcNow} - {msg.Severity}] {msg.ToString()}");
return Task.CompletedTask;
}
private async Task MainAsync()
{
await InitCommands();
await _client.LoginAsync(TokenType.Bot, _token);
await _client.StartAsync();
await Task.Delay(Timeout.Infinite);
}
private async Task InitCommands()
{
await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _services);
_client.MessageReceived += HandleCommandAsync;
}
private async Task HandleCommandAsync(SocketMessage messageParam)
{
var message = messageParam as SocketUserMessage;
if (message == null) return;
int argPos = 0;
if (!(message.HasStringPrefix("b.", ref argPos) ||
message.HasMentionPrefix(_client.CurrentUser, ref argPos)) ||
message.Author.IsBot)
return;
var context = new SocketCommandContext(_client, message);
await _commands.ExecuteAsync(context, argPos, _services);
}
}
这是一个模块的例子:
public class UserModule : ModuleBase<SocketCommandContext>
{
private readonly DiscordSocketClient _client;
private readonly CommandService _commands;
private readonly DatabaseContext _context;
private UserModule(DiscordSocketClient client, CommandService commands, DatabaseContext context)
{
_client = client;
_commands = commands;
_context = context;
}
[Command("user")]
public async Task Stats(IUser dUser = null)
{
Console.WriteLine(_context.ContextId);
}
}
但是,当我运行b.user
两次时,情况ContextId
是一样的。这导致我的应用程序出现严重的缓存问题,因为数据库在这个不和谐机器人和另一个应用程序之间共享。
我该怎么做才能DatabaseContext
在每次发出命令时创建一个?
解决方案
这是因为您的机器人是单个实例,因此注入的服务仅被解析一次。
而不是注入DbContext
注入 a IServiceScopeFactory
,并为每个请求创建一个单独的范围:
public class UserModule : ModuleBase<SocketCommandContext>
{
private readonly DiscordSocketClient _client;
private readonly CommandService _commands;
private readonly IServiceScopeFactory _scopeFactory;
private UserModule(DiscordSocketClient client, CommandService commands, IServiceScopeFactory scopeFactory)
{
_client = client;
_commands = commands;
_scopeFactory = scopeFactory;
}
[Command("user")]
public async Task Stats(IUser dUser = null)
{
using(var scope = _scopeFactory.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<MyDbContext>();
Console.WriteLine(dbContext.ContextId);
}
}
}
推荐阅读
- html - 为什么我的视差网站在滚动时如此滞后?
- c - Unix用C更新二进制文件
- wpf - WPF 标签文本碎片化
- function - 如何在 GLSL 中编写简单的加法或乘法函数
- python - 带有 numpy 随机集的奇怪 FFT 图
- filenet-p8 - 在 FileNet P8 中以编程方式将一个文件夹归档到另一个文件夹下
- c++ - std::dec、std::hex、std::oct 的二进制模拟
- amazon-web-services - EFS 会在实例终止后维护文件吗?
- javascript - 在 Google Apps 脚本中异步保存复选框
- powershell - 在表结构上添加 where-object?