Health Checks, Dependency Injection, and Scope #52086
Replies: 1 comment 1 reply
-
Health checks support publishing health reports at regular intervals. In order to support this health checks can't depend on a check running as part of a request. I suspect the code in the health check service explicitly makes a new scope so that your checks don't accidentally depend on the request context (and to allow using scoped services in a health check), otherwise when you go to publish a health report it'll fail due to not being in the context of a web request. The documentation should probably be explicit about this behavior. However it makes sense, the health of an application doesn't change depending on who's asking. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I'm facing a challenge with Health Checks and scope and I'm not quite sure what to do about it. My challenge seems to come down to this line of ASP.NET code.
Here's the issue:
We're using DI in Health Checks. I'm invoking Health Checks programmatically by DI'ing
HealthCheckService
into a controller and calling itsCheckHealthAsync
method. The controller method in question uses a policy that has a requirement authorization handler which references a scoped DI service that identifies who the caller is. That scoped "caller id" service is used later on in other services to get the caller id information, and since it's scoped, the information is available; however, if I try to get the caller id information from the same service DI'ed into my Health Check, the information is not available seemingly because of the line in question above, which creates a new scope for each health check that is run. Why create a new scope for every health check that is identified to be run according to the predicate?Is the answer that Health Checks "support" DI, meaning that DI is only properly supported when the health check in question is invoked via ASP.NET's internal uris, but if you invoke Health Checks via the public
HealthCheckService.CheckHealthAsync
method, then your DI scope is reset for each health check, which may break how scoped DI works in some scenarios because services are injected in a brand new scope instead of being used in the current scope, so you'll lose any information that was being retained in a scope-injected DI service before you programmatically invoked the health check?This seems like a bug to me.
If I invoke a health check via an endpoint that has a DI'ed
HealthCheckService.CheckHealthAsync
, that should be done using my current scope from the endpoint invocation instead of creating a new scope for each health check. Even if I invoke a set of health checks using an internal uri and ASP.NET's default invocation mechanism, I would have expected that to be done using a single scope for all health checks that are run instead of creating a new scope for each health check that is to be run based on the predicate that was passed in. Anything else seems contrary to how scoping and DI is designed to work, no? Otherwise the Health Check is DI'ing its services from a different container, losing access to anything scoped that may have been updated during authentication or during the invocation of the endpoint itself if it did any work with scoped services that it expected would be available to the Health Checks that it is about to run.All of that said, does anyone have any idea how I can preserve my current scope when running health checks programmatically? I can always create my own
ScopedHealthCheckService
and DI that instead ofHealthCheckService
to perform the execution within the same scope, but I'd really prefer not copying all of that code just to skip that one line.Beta Was this translation helpful? Give feedback.
All reactions