8.4 托管服务
【摘要】 有些工作是需要后台运行的,比如每天凌晨备份数据库。ASP.NET Core提供了托管服务来供我们编写后台代码。
托管服务只需要实现`IHostedService`即可,一般在开发时编写继承自`BackgroundService`的类,该类不进实现了`IHostedService`接口,并且处理了任务取消等逻辑,我们只需实现`BackgroundService`中定义的`ExecuteAsync`
8.4 托管服务
有些工作是需要后台运行的,比如每天凌晨备份数据库。ASP.NET Core提供了托管服务来供我们编写后台代码。
托管服务只需要实现IHostedService
即可,一般在开发时编写继承自BackgroundService
的类,该类不进实现了IHostedService
接口,并且处理了任务取消等逻辑,我们只需实现BackgroundService
中定义的ExecuteAsync
方法即可。
托管服务案例:
public class DemoBgService : BackgroundService
{
private ILogger<DemoBgService> logger;
public DemoBgService(ILogger<DemoBgService> logger)
{
this.logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await Task.Delay(5000);
string s = await File.ReadAllTextAsync("d:/1.txt");
await Task.Delay(20000);
logger.LogInformation(s);
}
}
在Program.cs中进行注册
builder.Services.AddHostedService<DemoBgService>();
托管服务会随着应用程序的启动而启动,如果托管服务出现异常且没有捕获,则整个程序就会崩掉,设置HostOptions.BackgroundServiceExceptionBehavior
设置为Ignore,这样会忽略这个异常,但是不推荐这种设置,推荐使用Try,并把异常输出到日志。
托管服务中使用依赖注入的陷阱
长生命周期的服务不能依赖短依赖周期的服务,托管服务为单例声明周期,所以不能在托管服务中注入范围或者瞬态服务。
可以通过构造方法注入IServiceScopeFactory
服务,它可以用来创建IserviceScope对象
案例:
public class ExplortStatisticBgService : BackgroundService
{
private readonly TestDbContext ctx;
private readonly ILogger<ExplortStatisticBgService> logger;
private readonly IServiceScope serviceScope;
//通过构造函数注入IServiceScopeFactory服务
public ExplortStatisticBgService(IServiceScopeFactory scopeFactory)
{
this.serviceScope = scopeFactory.CreateScope();//通过Factory创建IServiceScope对象
var sp = serviceScope.ServiceProvider;
//获得Scope对象
this.ctx = sp.GetRequiredService<TestDbContext>();
this.logger = sp.GetRequiredService<ILogger<ExplortStatisticBgService>>();
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)//长期的后台服务,一直运行在后台
{
try//使用try
{
await DoExecuteAsync();
await Task.Delay(5000);
}
catch (Exception ex)
{
logger.LogError(ex, "获取用户统计数据失败");
await Task.Delay(1000);
}
}
}
private async Task DoExecuteAsync()
{
var items = ctx.Users.GroupBy(u => u.CreationTime.Date)
.Select(e => new { Date = e.Key, Count = e.Count() });
StringBuilder sb = new StringBuilder();
sb.AppendLine($"Date:{DateTime.Now}");
foreach (var item in items)
{
sb.Append(item.Date).AppendLine($":{item.Count}");
}
await File.WriteAllTextAsync("d:/1.txt", sb.ToString());
logger.LogInformation($"导出完成");
}
public override void Dispose()
{
base.Dispose();
serviceScope.Dispose();//要释放
}
}
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)