Ale*_*bak 3 c# entity-framework-core .net-core asp.net-core-hosted-services
我有以下界面
internal interface IScopedProcessingService
{
Task DoWork(CancellationToken stoppingToken);
}
Run Code Online (Sandbox Code Playgroud)
和实施
public class ConsumeScopedServiceHostedService : BackgroundService
{
private readonly ILogger<ConsumeScopedServiceHostedService> _logger;
public ConsumeScopedServiceHostedService(IServiceProvider services,
ILogger<ConsumeScopedServiceHostedService> logger)
{
Services = services;
_logger = logger;
}
public IServiceProvider Services { get; }
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation(
"Consume Scoped Service Hosted Service running.");
await DoWork(stoppingToken);
}
private async Task DoWork(CancellationToken stoppingToken)
{
_logger.LogInformation(
"Consume Scoped Service Hosted Service is working.");
using (var scope = Services.CreateScope())
{
var scopedProcessingService =
scope.ServiceProvider
.GetRequiredService<IScopedProcessingService>();
await scopedProcessingService.DoWork(stoppingToken);
}
}
public override async Task StopAsync(CancellationToken stoppingToken)
{
_logger.LogInformation(
"Consume Scoped Service Hosted Service is stopping.");
await Task.CompletedTask;
}
}
Run Code Online (Sandbox Code Playgroud)
This code is from official Microsoft documentation. Background scoped services
And like in the documentation I have ScopedProcessingService but a few more difficult. Here is the code:
internal class ScopedProcessingService : IScopedProcessingService
{
private int _executionCount;
private readonly ILogger<ConsumeScopedServiceHostedService> _logger;
private readonly IPushRepository _pushRepository;
private readonly IPushTemplateRepository _pushTemplateRepository;
private readonly ISenderLogRepository _senderLogRepository;
private readonly IDistributionRepository _distributionRepository;
// services
private readonly IPushTemplateService _pushTemplateService;
private readonly ISendPushService _sendPushService;
public ScopedProcessingService(
ILogger<ConsumeScopedServiceHostedService> logger,
IPushTemplateService pushTemplateService, ISendPushService sendPushService,
IPushRepository pushRepository,
ISenderLogRepository senderLogRepository, IDistributionRepository distributionRepository,
IPushTemplateRepository pushTemplateRepository)
{
_logger = logger;
_pushTemplateService = pushTemplateService;
_sendPushService = sendPushService;
_pushRepository = pushRepository;
_senderLogRepository = senderLogRepository;
_distributionRepository = distributionRepository;
_pushTemplateRepository = pushTemplateRepository;
}
public async Task DoWork(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_executionCount = _senderLogRepository.SenderLogs.Count();
var logMessage = new StringBuilder();
logMessage.AppendLine($"??????? ???????? ? {_executionCount}.");
// get all templates. THIS CALL IS A SOURCE OF PROBLEMS
var templates = _pushTemplateRepository.PushTemplates.Where(x => x.isActive)
.Include(x => x.Messages)
.ThenInclude(x => x.PushLang)
.Include(x => x.Category)
.Include(x => x.AdvertiserPushTemplates)
.ThenInclude(x => x.Advertiser)
.ToList();
}
}
Run Code Online (Sandbox Code Playgroud)
In the Startup.cs class I use the following code to inject it:
services.AddHostedService<ConsumeScopedServiceHostedService>();
services.AddScoped<IScopedProcessingService, ScopedProcessingService>();
Run Code Online (Sandbox Code Playgroud)
The problem with this line var templates = _pushTemplateRepository.PushTemplates.Where(x => x.isActive). If I make some changes with a PushTemplate this changes will not have effect in the background task. And I will process old data. I mean, If I change name
for a PushTemplate, for example, with id = 15 from Name_1 to Name_2 than I will have Name_1 in the background task.
How to inject EF in a Scoped background service correctly? I not use clear EF context. I have repository layer.
public interface IPushTemplateRepository
{
IQueryable<PushTemplate> PushTemplates { get; }
void Save(PushTemplate pushTemplate);
void Delete(int templateid);
}
Run Code Online (Sandbox Code Playgroud)
And implementation
public class PushTemplateRepository : IPushTemplateRepository
{
private readonly ApplicationDbContext _applicationContext;
public PushTemplateRepository(ApplicationDbContext applicationContext)
{
_applicationContext = applicationContext;
}
public IQueryable<PushTemplate> PushTemplates => _applicationContext.PushTemplates;
public void Save(PushTemplate pushTemplate)
{
// ...
}
public void Delete(int templateid)
{
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
问题是在DbContext具有无限循环的单个范围中捕获。
作用域永远不会被释放,因此将保留它在创建作用域时拥有的数据。
每次需要所需功能时,重构以将循环移出一个级别并创建一个新范围。
消费范围服务托管服务
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
_logger.LogInformation("Consume Scoped Service Hosted Service is working.");
while (!stoppingToken.IsCancellationRequested) {
using (var scope = Services.CreateScope()) {
IServiceProvider serviceProvider = scope.ServiceProvider;
var service = serviceProvider.GetRequiredService<IScopedProcessingService>();
await service.DoWork(stoppingToken);
}
//Add a delay between executions.
await Task.Delay(SomeIntervalBetweenCalls, stoppingToken);
}
}
Run Code Online (Sandbox Code Playgroud)
范围处理服务
//...
public async Task DoWork(CancellationToken stoppingToken) {
_executionCount = _senderLogRepository.SenderLogs.Count();
var logMessage = new StringBuilder();
logMessage.AppendLine($"??????? ???????? ? {_executionCount}.");
// get all templates.
var templates = _pushTemplateRepository.PushTemplates.Where(x => x.isActive)
.Include(x => x.Messages)
.ThenInclude(x => x.PushLang)
.Include(x => x.Category)
.Include(x => x.AdvertiserPushTemplates)
.ThenInclude(x => x.Advertiser)
.ToList();
//...
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
585 次 |
| 最近记录: |