欢迎访问 生活随笔!

凯发k8官方网

当前位置: 凯发k8官方网 > 编程语言 > >内容正文

asp.net

asp.net core 3.x控制ihostedservice启动顺序浅探 -凯发k8官方网

发布时间:2023/12/4 32 豆豆
凯发k8官方网 收集整理的这篇文章主要介绍了 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

想写好中间件,这是基础。

今天这个内容,基于于asp.net core 3.x。

从3.x开始,asp.net core使用了通用主机模式。它将webhostbuilder放到了通用的ihost之上,这样可以确保kestrel可以运行在ihostedservice中。

我们今天就来研究一下这个启动方式和启动顺序。

通常情况下,ihostedservice的任何实现在添加到startup.configureservices()后,都会在genericwebhostservice之前启动。

这是微软官方给出的图。

这个图展示了在ihost上调用runasync()时的启动顺序(后者又调用startasync())。对我们来说,最重要的部分是启动的ihostedservices。从图上也可以看到,自定义ihostedservices先于genericwebhostsevice启动。

我们来看一个简单的例子:

public class startuphostedservice : ihostedservice {private readonly ilogger _logger;public startuphostedservice(ilogger logger){_logger = logger;}public task startasync(cancellationtoken cancellationtoken){_logger.loginformation("starting ihostedservice registered in startup");return task.completedtask;}public task stopasync(cancellationtoken cancellationtoken){_logger.loginformation("stopping ihostedservice registered in startup");return task.completedtask;} }

我们做一个简单的ihostedservice。希望加到startup.cs中:

public class startup {public void configureservices(iservicecollection services){services.addhostedservice();} }

运行代码:

info: demo.startuphostedservice[0]            # 这是上边的startuphostedservicestarting ihostedservice registered in startup info: microsoft.hosting.lifetime[0]            # 这是genericwebhostsevicenow listening on: https://localhost:5001 info: microsoft.hosting.lifetime[0]application started. press ctrl c to shut down.

正如预期的那样,ihostedservice首先执行,然后是genericwebhostsevice。applicationlifetime事件在所有ihostedservices执行之后触发。无论在什么地方注册了startup.configureservices()中的ihostedservice, genericwebhostsevice都在最后启动。

那么问题来了,为什么genericwebhostsevice在最后启动?

先看看多个ihostedservice的情况。

当有多个ihostedservice的实现加入到startup.configureservices()时,运行次序取决于它被加入的次序。

看例子:

public class service1 : ihostedservice {private readonly ilogger _logger;public service1(ilogger logger){_logger = logger;}public task startasync(cancellationtoken cancellationtoken){_logger.loginformation("starting service1");return task.completedtask;}public task stopasync(cancellationtoken cancellationtoken){_logger.loginformation("stoping service1");return task.completedtask;} } public class service2 : ihostedservice {private readonly ilogger _logger;public service2(ilogger logger){_logger = logger;}public task startasync(cancellationtoken cancellationtoken){_logger.loginformation("starting service2");return task.completedtask;}public task stopasync(cancellationtoken cancellationtoken){_logger.loginformation("stoping service2");return task.completedtask;} }

startup.cs:

public class startup {public void configureservices(iservicecollection services){services.addhostedservice();services.addhostedservice();} }

运行:

info: demo.service1[0]                # 这是service1starting service1 info: demo.service2[0]                # 这是service2starting service2 info: microsoft.hosting.lifetime[0]        # 这是genericwebhostsevicenow listening on: https://localhost:5001 info: microsoft.hosting.lifetime[0]application started. press ctrl c to shut down.

那么,genericwebhostsevice是什么时候注册的?

我们看看另一个文件program.cs:

public class program {public static void main(string[] args){createhostbuilder(args).build().run();}public static ihostbuilder createhostbuilder(string[] args) =>host.createdefaultbuilder(args).configurewebhostdefaults(webbuilder =>            # 这是genericwebhostsevice注册的位置{webbuilder.usestartup();}); }

configurewebhostdefaults扩展方法调用configurewebhost方法,该方法执行startup.configureservices(),然后注册genericwebhostservice。整理一下代码,就是下面这个样子:

public static ihostbuilder configurewebhost(this ihostbuilder builder, action configure) {var webhostbuilder = new genericwebhostbuilder(builder);configure(webhostbuilder);builder.configureservices((context, services) => services.addhostedservice());return builder; }

这样可以确保genericwebhostservice总是最后运行,以保持通用主机实现和webhost(已弃用)实现之间的行为一致。

因此,可以采用同样的方式,让ihostedservice在genericwebhostservice后面启动。

在大多数情况下,在genericwebhostservice之前启动ihostedservices就可以满足常规的应用。但是,genericwebhostservice还负责构建应用程序的中间件管道。如果ihostedservice依赖于中间件管道或路由,那么就需要将它的启动延迟到genericwebhostservice完成之后。

根据上面的说明,在genericwebhostservice之后执行ihostedservice的唯一方法是将它添加到genericwebhostservice之后的di容器中。这意味着你必须跳出startup.configureservices(),在调用configurewebhostdefaults之后,直接在ihostbuilder上调用configureservices():

public class programhostedservice : ihostedservice {private readonly ilogger _logger;public programhostedservice(ilogger logger){_logger = logger;}public task startasync(cancellationtoken cancellationtoken){_logger.loginformation("starting programhostedservice registered in program");return task.completedtask;}public task stopasync(cancellationtoken cancellationtoken){_logger.loginformation("stopping programhostedservice registered in program");return task.completedtask;} }

加到program.cs中:

public class program {public static void main(string[] args){createhostbuilder(args).build().run();}public static ihostbuilder createhostbuilder(string[] args) =>host.createdefaultbuilder(args).configurewebhostdefaults(webbuilder =>            # 这是genericwebhostsevice注册的位置{webbuilder.usestartup();}).configureservices(services => services.addhostedservice());            # 这是programhostedservice注册的位置 }

看输出:

info: demo.startuphostedservice[0]            # 这是startuphostedservicestarting ihostedservice registered in startup info: microsoft.hosting.lifetime[0]            # 这是genericwebhostsevicenow listening on: https://localhost:5001 info: demo.programhostedservice[0]            # 这是programhostedservicestarting programhostedservice registered in program info: microsoft.hosting.lifetime[0]application started. press ctrl c to shut down.

同样,在关闭应用时,ihostedservices被反向停止,所以programhostedservice首先停止,接着是genericwebhostsevice,最后是startuphostedservice:

info: microsoft.hosting.lifetime[0]application is shutting down... info: demo.programhostedservice[0]stopping programhostedservice registered in program info: demo.startuphostedservice[0]stopping ihostedservice registered in startup

最后总结一下:

ihostedservices的执行顺序与它们在startup.configureservices()中添加到di容器中的顺序相同。运行侦听http请求的kestrel服务器的genericwebhostsevice总是注册的ihostedservices之后运行。

要在genericwebhostsevice之后启动ihostedservice,需要在program.cs中的ihostbuilder上的configureservices()扩展方法中进行注册。

(全文完)

本文的代码在:https://github.com/humornif/demo-code/tree/master/0024/demo

总结

以上是凯发k8官方网为你收集整理的的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得凯发k8官方网网站内容还不错,欢迎将凯发k8官方网推荐给好友。

网站地图