Troubleshooting issues with AsyncLocal when used within a middleware
- The TokenAuthenticationMiddleware (simplified here) is supposed to intercept the request, validate the tokens, retrieve corpId and userId value from it and override the values in the
DefaultServiceContextscoped instance.- In this example, to keep things simple, we have replaced the token with alternate
x-auth-headers that should trump the standardx-headers
- In this example, to keep things simple, we have replaced the token with alternate
- There are 2 problems here:
- By having the
TokenAuthenticationMiddlewarehave the following DI dependency chain:ILog -> DefaultServiceContext -> ISecurityTokenAccessor- We effectively create this conundrum where
DefaulServiceContextis resolved before the middleware is able to set the values inISecurityTokenAccessorinstance - We can therefore never overwrite the corp-id and user-id values with the
x-auth-header values
- We effectively create this conundrum where
- Even without the problem above, AsyncLocal should never keep values from the previous request since they are being set in the middleware, which should be a leaf... (at least that's my understanding...)
- This is the part that is the most confusing...
- Interestingly, when running the same scenario using
Microsoft.AspNetCore.TestHost, the behavior above doesn't occur
- By having the
For convenience, use the Postman export located in artifacts/TestAsyncLocalMiddleware.postman_collection.json file.
- Pre-requisite
- Start the service using following command:
> dotnet run -p ./TestAsyncLocalMiddleware
- Make an HTTP Request to service as follows:
-
GET /api/values
- Headers:
- x-corp-id: 1
- x-user-id: 5
- x-auth-corp-id: 10
- x-auth-user-id: 50
- Headers:
-
The response returns successfully 1 and 5 (which is already an issue since the dependency chain causes the DefaultServiceContext to be resolved before the middleware overwrites the values)
- Make a second HTTP request to service as follows:
- GET /api/values
- Headers:
- x-corp-id: 2
- x-user-id: 8
- x-auth-corp-id: 20
- x-auth-user-id: 80
- Headers:
- The middleware crashes because the
SecurityTokenAccessorkeeps items from first request, even though it is backed by AsyncLocal which should guarantee the 2 requests use different logical scopes.
- The issue is due to the fact the
TokenAuthenticationMiddlewarehas a dependency toILogwhich itself has a dependency toDefaultServiceContext, which itself has a dependency toISecurityTokenAccessor.- For some reason, this chain of dependency seems to have an effect on the scope of AsyncLocal... It's not very clear why though...
- Interestingly as well, when running the test using
Microsoft.AspNetCore.TestHost'sTestServer, the behavior changes and the values are not being persisted in AsyncLocal between requests... - Another interesting clue is when running this scenario in IIS Express, the behavior is not occurring as well... Could it be a bug in Kestrel host?