[英]Where am I supposed to start persistent background tasks in ASP.NET Core?
In my web application (ASP.NET Core), I want to run a job in the background that is listening to a remote server, calculating some results and pushing it to the client on Pusher (a websocket). 在我的Web应用程序(ASP.NET Core)中,我想在后台运行一个正在侦听远程服务器的作业,计算一些结果并将其推送到Pusher上的客户端(websocket)。
I'm not sure where I'm supposed to start this task. 我不确定我应该在哪里开始这个任务。 Currently I start it at the end of
目前我在最后开始
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
in Startup.cs 在Startup.cs中
but I think there is something wrong about that, it doesn't make sense to start background jobs in a method called "Configure". 但我觉得这有点不对,在一个名为“Configure”的方法中启动后台作业是没有意义的。 I was expecting to find a Start method somewhere
我期待在某个地方找到一个Start方法
Also, when I try to use EF Core to generate initial database migration file , it actually executes that method and starts my tasks.. which clearly doesn't make any sense: 此外,当我尝试使用EF Core 生成初始数据库迁移文件时 ,它实际上执行该方法并启动我的任务..这显然没有任何意义:
dotnet ef migrations add InitialCreate
running that from console creates migration code which will be used to create the database on SQL Server based on my data models. 从控制台运行它会创建迁移代码,该代码将用于根据我的数据模型在SQL Server上创建数据库。
Why isn't there a method where I can start some a Task? 为什么没有一种方法可以开始一个任务? I don't want this to be on a separate process, it really doesn't need its own process and it is essentially a part of the web server because it does communicate with the client (browser) via a websocket, so it makes sense to run it as part of the web server.
我不希望这是一个单独的进程,它实际上不需要自己的进程,它本质上是Web服务器的一部分,因为它确实通过websocket与客户端(浏览器)进行通信,所以它是有道理的将其作为Web服务器的一部分运行。
I believe you're looking for this 我相信你在寻找这个
https://blogs.msdn.microsoft.com/cesardelatorre/2017/11/18/implementing-background-tasks-in-microservices-with-ihostedservice-and-the-backgroundservice-class-net-core-2-x/ https://blogs.msdn.microsoft.com/cesardelatorre/2017/11/18/implementing-background-tasks-in-microservices-with-ihostedservice-and-the-backgroundservice-class-net-core-2-x/
And i did a 2 hour self-proclaimed-award-winning hackathon against myself to learn abit of that. 我做了一个2小时的自我屡获殊荣的黑客马拉松对我自己去学习。
https://github.com/nixxholas/nautilus https://github.com/nixxholas/nautilus
You can refer the injections here and implement the abstracts from there too. 您可以在此处参考注射并从那里实施摘要。
Many MVC projects are not really required to operate persistent background tasks. 许多MVC项目并不是真正需要运行持久性后台任务。 This is why you don't see them baked into a fresh new project via the template.
这就是为什么你没有看到他们通过模板烘焙到一个全新的项目。 It's better to provide developers an interface to tap on and go ahead with it.
最好为开发人员提供一个界面来点击并继续使用它。
Also, with regards to opening that socket connection for such background tasks, I have yet to establish a solution for that. 此外,关于为这些后台任务打开该套接字连接,我还没有为此建立解决方案。 As far as I know/did, I was only able to broadcast payload to clients that are connected to my own socketmanager so you'll have to look elsewhere for that.
据我所知/做过,我只能将有效负载广播到连接到我自己的socketmanager的客户端,因此你必须在其他地方查找。 I'll definitely beep if there is anything regarding websockets in an IHostedService.
如果在IHostedService中有关于websockets的任何内容,我肯定会发出哔哔声。
Ok anyway here's what happens. 好吧无论如何这里发生了什么。
Put this somewhere in your project, its more of an interface for you to overload with to create your own task 把它放在项目的某个地方,它更多的是一个让你重载以创建自己的任务的界面
/// 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();
}
}
Here's how you can actually use it 以下是您实际使用它的方法
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);
}
}
}
}
If you noticed, there's a bonus there. 如果你注意到,那里有奖金。 You'll have to use a servicescope in order to access db operations because its a singleton.
您必须使用服务范围才能访问数据库操作,因为它是一个单例。
Inject your service in 注入您的服务
// Background Service Dependencies
services.AddSingleton<IHostedService, IncomingEthTxService>();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.