gpt4 book ai didi

c# - 在 ASP.NET Core 中添加数据库驱动的调度程序的正确位置是什么?

转载 作者:行者123 更新时间:2023-11-30 13:54:13 25 4
gpt4 key购买 nike

我在 ASP.Net Core 应用程序的 Startup 类中添加了一个 Timer。它会在某个时间段触发并执行诸如记录示例文本之类的操作。我需要它能够执行数据库驱动的操作,例如向表中添加记录。所以我尝试从 DI 获取 AppDbContext 但它始终为空。请看代码:

    public class Scheduler
{
static Timer _timer;
static bool _isStarted;
static ILogger<Scheduler> _logger;
const int dueTimeMin = 1;
const int periodMin = 1;

public static void Start(IServiceProvider serviceProvider)
{
if (_isStarted)
throw new Exception("Currently is started");

_logger = (ILogger<Scheduler>)serviceProvider.GetService(typeof(ILogger<Scheduler>));

var autoEvent = new AutoResetEvent(false);
var operationClass = new OperationClass(serviceProvider);
_timer = new Timer(operationClass.DoOperation, autoEvent, dueTimeMin * 60 * 1000, periodMin * 60 * 1000);
_isStarted = true;
_logger.LogInformation("Scheduler started");
}
}

public class OperationClass
{
IServiceProvider _serviceProvider;
ILogger<OperationClass> _logger;
AppDbContext _appDbContext;

public OperationClass(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
_logger = (ILogger<OperationClass>)serviceProvider.GetService(typeof(ILogger<OperationClass>));
_appDbContext = (AppDbContext)_serviceProvider.GetService(typeof(AppDbContext));
}

public void DoOperation(Object stateInfo)
{
try
{
_logger.LogInformation("Timer elapsed.");

if (_appDbContext == null)
throw new Exception("appDbContext is null");

_appDbContext.PlayNows.Add(new PlayNow
{
DateTime = DateTime.Now
});

_appDbContext.SaveChanges();
}
catch (Exception exception)
{
_logger.LogError($"Error in DoOperation: {exception.Message}");
}
}
}

这是来自 Startup 的代码:

        public Startup(IHostingEnvironment env, IServiceProvider serviceProvider)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();

AppHelper.InitializeMapper();
Scheduler.Start(serviceProvider);
}

我想我在错误的地方调用了 Scheduler.Start。似乎 AppDbContext 还没有准备好。

调用 Scheduler.Start 的正确位置是什么?

最佳答案

当您在后台线程上运行代码时,您应该始终在该后台线程上为您的 DI 容器开始一个新的“范围”并从该范围解析。

那么你应该做的是:

  • 在事件中创建一个新范围
  • 从该范围解析OperationClass
  • OperationClass 内部只依赖于构造函数注入(inject);不在Service Location .

您的代码应如下所示:

public class Scheduler
{
static Timer _timer;
const int dueTimeMin = 1;
const int periodMin = 1;

public static void Start(IServiceScopeFactory scopeFactory)
{
if (scopeFactory == null) throw new ArgumentNullException("scopeFactory");
_timer = new Timer(_ =>
{
using (var scope = new scopeFactory.CreateScope())
{
scope.GetRequiredService<OperationClass>().DoOperation();
}
}, new AutoResetEvent(false), dueTimeMin * 60 * 1000, periodMin * 60 * 1000);
}
}

这里Start依赖于IServiceScopeFactoryIServiceScopeFactory 可以从 IServiceProvider 解析。

您的 OperationClass 将变成如下所示:

public class OperationClass
{
private readonly ILogger<OperationClass> _logger;
private readonly AppDbContext _appDbContext;

public OperationClass(ILogger<OperationClass> logger, AppDbContext appDbContext)
{
if (logger == null) throw new ArgumentNullException(nameof(logger));
if (appDbContext == null) throw new ArgumentNullException(nameof(appDbContext));

_logger = logger;
_appDbContext = appDbContext;
}

public void DoOperation()
{
try
{
_logger.LogInformation("DoOperation.");

_appDbContext.PlayNows.Add(new PlayNow
{
DateTime = DateTime.Now
});

_appDbContext.SaveChanges();
}
catch (Exception exception)
{
_logger.LogError($"Error in DoOperation: {exception}");
}
}
}

虽然不是特定于 .NET Core 容器的文档,this documentation提供了有关如何在多线程应用程序中使用 DI 容器的更详细信息。

关于c# - 在 ASP.NET Core 中添加数据库驱动的调度程序的正确位置是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45128033/

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