Holes in my dependency injection knowledge: IMultiTenantContextAccessor as a Singleton #661
-
Hello everyone. I have Finbuckle up and running in my app and it works, but I just want to understand how it works. I see that on an incoming request the middleware pulls the tenantId off the claim (at least in my case). What I don't understand is how the dependancy injection stack is working.
How is the middleware getting a scoped version of the IMultiTenantContextAccessor service to set the MultiTenantContext on ?
I am sure it is sitting right in front of my face, just not seeing it. Thanks for any enlightenment. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
Hi, you ask a very good question. The answer, currently, is that the accessor implementation uses an AsyncLocal instance. AsyncLocals have some special behavior whenever an async/await happens so that each new continuation gets its own copy of the instance from it's parent. So in the middleware pipeline pretty much immediately triggers an async/await so there is no conflict for tenants. Some downsides exist though. Performance is impacted. Also any code in the async/await stack "higher" than the multitenant middleware will not see the tenants on the return trip through the pipeline. I've also toyed with an implementation that instead uses a scoped DI variable or the HttpContext property bag. I welcome any recommendations. For non ASP.NET Core scenarios the current implementation isn't great. |
Beta Was this translation helpful? Give feedback.
-
Thank you so much for the explanation! I thought I was going crazy, I will look more into this AsyncLocal, its not something I have used before. It is all working great so far, just wanted to fill in the knowledge gap. |
Beta Was this translation helpful? Give feedback.
Hi, you ask a very good question.
The answer, currently, is that the accessor implementation uses an AsyncLocal instance.
AsyncLocals have some special behavior whenever an async/await happens so that each new continuation gets its own copy of the instance from it's parent. So in the middleware pipeline pretty much immediately triggers an async/await so there is no conflict for tenants.
Some downsides exist though. Performance is impacted. Also any code in the async/await stack "higher" than the multitenant middleware will not see the tenants on the return trip through the pipeline.
I've also toyed with an implementation that instead uses a scoped DI variable or the HttpContext property bag.