简体   繁体   English

如何确定在关机时调用 IHostedServices 的顺序?

[英]How to determine in which order IHostedServices are being called at shutdown?

I'm maintaining a integration package that allows my users to integrate my library with ASP.NET Core.我正在维护一个集成 package,它允许我的用户将我的库与 ASP.NET 核心集成。 This package must be compatible with all versions of ASP.NET Core starting at 2.1.此 package 必须与从 2.1 开始的 ASP.NET 内核的所有版本兼容。 At application shutdown my integration package must be able to execute asynchronous cleanup, and unfortunately can't take a dependency on IAsyncDisposable through Microsoft.Bcl.AsyncInterfaces (see below).在应用程序关闭时,我的集成 package 必须能够执行异步清理,不幸的是不能通过Microsoft.Bcl.AsyncInterfaces依赖IAsyncDisposable (见下文)。

The only way this, therefore, seems feasible is by registering an IHostedService implementation.因此,这似乎可行的唯一方法是注册IHostedService实现。 It's StopAsync method is called at shutdown:它的StopAsync方法在关机时被调用:

public sealed class ShutdownHostedService : IHostedService
{
    public MyLibaryCleanupObject Obj;
    public Task StartAsync(CancellationToken token) => Task.CompletedTask;
    public Task StopAsync(CancellationToken token) => this.Obj.CleanupAsync();
}

services.AddSingleton<IHostedService>(new ShutdownHostedService { Obj = ... });

Application developers, however, can of course add their own IHostedService implementations, which might interact with my library.然而,应用程序开发人员当然可以添加他们自己的IHostedService实现,这可能与我的库进行交互。 This is why it is important for my own IHostedService implementation to be called last.这就是为什么最后调用我自己的IHostedService实现很重要的原因。 But here lies the problem.但问题就在这里。

With the introduction of ASP.NET Core 2.1 application developers can choose between using the new Microsoft.Extensions.Hosting.Host and the (now deprecated) Microsoft.AspNetCore.WebHost .随着 ASP.NET Core 2.1 的引入,应用程序开发人员可以在使用新的Microsoft.Extensions.Hosting.Host和(现已弃用) Microsoft.AspNetCore.WebHost之间进行选择。 With WebHost , at shutdown, IHostedService implementations are called in order of registration, whereas with Host , IHostedService implementations are called in opposite order of registration.使用WebHost ,在关闭时,按注册顺序调用IHostedService实现,而使用Host ,按相反的注册顺序调用IHostedService实现。

This is problematic for me, because my hosted service should be called last.这对我来说是个问题,因为我的托管服务应该最后调用。 As application developers might use my integration package in their existing ASP.NET Core application, they might still use WebHost , which is why it is important to support that scenario.由于应用程序开发人员可能在他们现有的 ASP.NET 核心应用程序中使用我的集成 package ,他们可能仍然使用WebHost ,这就是支持该方案很重要的原因。

Question: What would be a reliable way to determine in what 'mode' the ASP.NET Core application runs, so I can decide to add my hosted service first or last?问题:确定 ASP.NET 核心应用程序运行在什么“模式”下的可靠方法是什么,所以我可以决定首先或最后添加我的托管服务?

Alternatively, to prevent falling into the XY-problem trap, I'm open to completely different solutions that solve my problem of implementing "asynchronous shutdown".或者,为了防止陷入 XY 问题陷阱,我愿意接受完全不同的解决方案来解决我实现“异步关闭”的问题。

Note on IAsyncDisposable :关于IAsyncDisposable的注意事项:

One solution that would come to mind (as Ian rightfully notes in the comments) is to add an IAsyncDisposable Singleton registration to the ServiceCollection .想到的一种解决方案(正如 Ian 在评论中正确指出的那样)是将IAsyncDisposable Singleton 注册添加到ServiceCollection This would allow asynchronous cleanup at shutdown.这将允许在关闭时进行异步清理。 Unfortunately, due to constraints (explained here ) it's impossible for my integration package to take a dependency on Microsoft.Bcl.AsyncInterfaces and, therefore, not on IAsyncDisposable .不幸的是,由于限制(在此处解释),我的集成 package 不可能依赖Microsoft.Bcl.AsyncInterfaces ,因此不能依赖IAsyncDisposable This is an unfortunate situation that certainly complicates the matter.这是一个不幸的情况,肯定会使事情复杂化。 As a matter of fact, the reason for not being able to take a dependency on IAsyncDisposable is the reason I'm looking for alternative ways of implementing asynchronous shutdown code.事实上,不能依赖IAsyncDisposable的原因是我正在寻找实现异步关闭代码的替代方法的原因。

The solution I end up using is identical to the solution chosen by Microsoft's Microsoft.Extensions.Hosting.Internal.Host class and doesn't involve using IHostedService instances.我最终使用的解决方案与 Microsoft 的Microsoft.Extensions.Hosting.Internal.Host class 选择的解决方案相同,并且不涉及使用IHostedService实例。 The Host class contains the following Dispose method: Host class 包含以下Dispose方法:

public void Dispose()
{
    this.DisposeAsync().GetAwaiter().GetResult();
}

This might raise some eyebrows and might be seen as a bad practice, but don't forget that:这可能会引起一些人的注意,并且可能被视为一种不好的做法,但不要忘记:

  • This code is guaranteed to run in the context of ASP.NET Core, where this code can't cause a deadlock此代码保证在 ASP.NET 内核的上下文中运行,此代码不会导致死锁
  • This code runs just once at shutdown, so performance isn't an issue here.此代码在关机时只运行一次,因此性能在这里不是问题。

This is why Microsoft's Host class can take this approach, and it means that it is a safe approach for my library to do as well.这就是为什么微软的Host class 可以采用这种方法的原因,这意味着我的库也可以采用这种方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM