我应该在 ASP.NET Core 中的哪里开始持续后台任务?
Where am I supposed to start persistent background tasks in ASP.NET Core?
在我的 Web 应用程序(ASP.NET 核心)中,我想 运行 在后台侦听远程服务器的作业,计算一些结果并将其推送到 Pusher 上的客户端(网络套接字)。
我不确定应该从哪里开始这项任务。目前我在
结束时开始
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
在Startup.cs
但我认为这有问题,在名为 "Configure" 的方法中启动后台作业没有意义。我期待在某处找到 Start 方法
此外,当我尝试使用 EF Core generate initial database migration file 时,它实际上执行了该方法并开始了我的任务..这显然没有任何意义:
dotnet ef migrations add InitialCreate
运行从控制台创建的迁移代码将用于根据我的数据模型在 SQL 服务器上创建数据库。
为什么没有我可以启动某些任务的方法?我不希望它在一个单独的进程中,它真的不需要自己的进程,它本质上是网络服务器的一部分,因为它确实通过 websocket 与客户端(浏览器)通信,所以这是有道理的运行 将其作为网络服务器的一部分。
我相信你正在寻找这个
我还参加了 2 小时的 self-proclaimed-award-winning 黑客马拉松比赛来学习一点点。
https://github.com/nixxholas/nautilus
您可以在此处参考注入并从那里实现抽象。
许多 MVC 项目并不是真正需要运行持久后台任务。这就是为什么您没有看到它们通过模板被烘焙到一个全新的项目中。最好为开发者提供一个界面,让他们点击并继续它。
此外,关于为此类后台任务打开套接字连接,我还没有为此建立解决方案。就我 know/did 而言,我只能向连接到我自己的 socketmanager 的客户端广播有效负载,因此您必须到别处寻找。如果 IHostedService 中有任何关于 websockets 的内容,我肯定会发出哔哔声。
好吧无论如何这就是发生的事情。
把它放在你项目的某个地方,它更像是一个接口,供你重载以创建你自己的任务
/// Copyright(c) .NET Foundation.Licensed under the Apache License, Version 2.0.
/// <summary>
/// Base class for implementing a long running <see cref="IHostedService"/>.
/// </summary>
public abstract class BackgroundService : IHostedService, IDisposable
{
protected readonly IServiceScopeFactory _scopeFactory;
private Task _executingTask;
private readonly CancellationTokenSource _stoppingCts =
new CancellationTokenSource();
public BackgroundService(IServiceScopeFactory scopeFactory) {
_scopeFactory = scopeFactory;
}
protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
public virtual Task StartAsync(CancellationToken cancellationToken)
{
// Store the task we're executing
_executingTask = ExecuteAsync(_stoppingCts.Token);
// If the task is completed then return it,
// this will bubble cancellation and failure to the caller
if (_executingTask.IsCompleted)
{
return _executingTask;
}
// Otherwise it's running
return Task.CompletedTask;
}
public virtual async Task StopAsync(CancellationToken cancellationToken)
{
// Stop called without start
if (_executingTask == null)
{
return;
}
try
{
// Signal cancellation to the executing method
_stoppingCts.Cancel();
}
finally
{
// Wait until the task completes or the stop token triggers
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite,
cancellationToken));
}
}
public virtual void Dispose()
{
_stoppingCts.Cancel();
}
}
实际使用方法如下
public class IncomingEthTxService : BackgroundService
{
public IncomingEthTxService(IServiceScopeFactory scopeFactory) : base(scopeFactory)
{
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
using (var scope = _scopeFactory.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<NautilusDbContext>();
Console.WriteLine("[IncomingEthTxService] Service is Running");
// Run something
await Task.Delay(5, stoppingToken);
}
}
}
}
如果您注意到了,这里有一个奖励。您必须使用服务范围才能访问数据库操作,因为它是单例。
将您的服务注入
// Background Service Dependencies
services.AddSingleton<IHostedService, IncomingEthTxService>();
在我的 Web 应用程序(ASP.NET 核心)中,我想 运行 在后台侦听远程服务器的作业,计算一些结果并将其推送到 Pusher 上的客户端(网络套接字)。
我不确定应该从哪里开始这项任务。目前我在
结束时开始 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
在Startup.cs
但我认为这有问题,在名为 "Configure" 的方法中启动后台作业没有意义。我期待在某处找到 Start 方法
此外,当我尝试使用 EF Core generate initial database migration file 时,它实际上执行了该方法并开始了我的任务..这显然没有任何意义:
dotnet ef migrations add InitialCreate
运行从控制台创建的迁移代码将用于根据我的数据模型在 SQL 服务器上创建数据库。
为什么没有我可以启动某些任务的方法?我不希望它在一个单独的进程中,它真的不需要自己的进程,它本质上是网络服务器的一部分,因为它确实通过 websocket 与客户端(浏览器)通信,所以这是有道理的运行 将其作为网络服务器的一部分。
我相信你正在寻找这个
我还参加了 2 小时的 self-proclaimed-award-winning 黑客马拉松比赛来学习一点点。
https://github.com/nixxholas/nautilus
您可以在此处参考注入并从那里实现抽象。
许多 MVC 项目并不是真正需要运行持久后台任务。这就是为什么您没有看到它们通过模板被烘焙到一个全新的项目中。最好为开发者提供一个界面,让他们点击并继续它。
此外,关于为此类后台任务打开套接字连接,我还没有为此建立解决方案。就我 know/did 而言,我只能向连接到我自己的 socketmanager 的客户端广播有效负载,因此您必须到别处寻找。如果 IHostedService 中有任何关于 websockets 的内容,我肯定会发出哔哔声。
好吧无论如何这就是发生的事情。
把它放在你项目的某个地方,它更像是一个接口,供你重载以创建你自己的任务
/// Copyright(c) .NET Foundation.Licensed under the Apache License, Version 2.0.
/// <summary>
/// Base class for implementing a long running <see cref="IHostedService"/>.
/// </summary>
public abstract class BackgroundService : IHostedService, IDisposable
{
protected readonly IServiceScopeFactory _scopeFactory;
private Task _executingTask;
private readonly CancellationTokenSource _stoppingCts =
new CancellationTokenSource();
public BackgroundService(IServiceScopeFactory scopeFactory) {
_scopeFactory = scopeFactory;
}
protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
public virtual Task StartAsync(CancellationToken cancellationToken)
{
// Store the task we're executing
_executingTask = ExecuteAsync(_stoppingCts.Token);
// If the task is completed then return it,
// this will bubble cancellation and failure to the caller
if (_executingTask.IsCompleted)
{
return _executingTask;
}
// Otherwise it's running
return Task.CompletedTask;
}
public virtual async Task StopAsync(CancellationToken cancellationToken)
{
// Stop called without start
if (_executingTask == null)
{
return;
}
try
{
// Signal cancellation to the executing method
_stoppingCts.Cancel();
}
finally
{
// Wait until the task completes or the stop token triggers
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite,
cancellationToken));
}
}
public virtual void Dispose()
{
_stoppingCts.Cancel();
}
}
实际使用方法如下
public class IncomingEthTxService : BackgroundService
{
public IncomingEthTxService(IServiceScopeFactory scopeFactory) : base(scopeFactory)
{
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
using (var scope = _scopeFactory.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<NautilusDbContext>();
Console.WriteLine("[IncomingEthTxService] Service is Running");
// Run something
await Task.Delay(5, stoppingToken);
}
}
}
}
如果您注意到了,这里有一个奖励。您必须使用服务范围才能访问数据库操作,因为它是单例。
将您的服务注入
// Background Service Dependencies
services.AddSingleton<IHostedService, IncomingEthTxService>();