MediatR: Mediator breaks out of the logical CallContext
I’m having trouble with my mediator pipeline.
I’m using the IRequestPostProcessor to implement both some workflow behavior and generic logging tasks.
Some of my mediator handlers are requesting the current user from HttpContext.Current.User, and for the most part, this works just fine. But lately we have experienced that the http context is not available.
I’m not 100% sure about this, but I think it’s a question of setting continueOnCapturedContext to false when calling next() in the RequestPostProcessorBehavior-implementation. At least, replacing the implementation with my own implementation that does not include the .ConfigureAwait(false) seems to solve the problem.
Is this a known problem? Is there a known solution?
(We’re still on MediatR 3.01)
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 39 (39 by maintainers)
@jbogard yes. Since MediateR is a general purpose in-process messaging library I’d say
ConfigureAwait(false)could be argued as a good default value. Especially considering that MediatR encourages you to have SRP handlers that can return responses and those responses can then be assigned to something like the ViewModel or the UI. With that design you should never need to access something that is context-aware inside a handler, thusConfigureAwait(false)actually enforces that design decision.Stay away from
ConfigureAwait(false)and you should be good.By staying away I mean code that accesses the ambient context (eg HttpContent.Current )should not be asynchronously executed using
ConfigureAwait(false).Net Framework 4.7.1 introduces the concept of Execution steps that seems to address this issue although I have never tested this myself. https://blogs.msdn.microsoft.com/dotnet/2017/09/13/net-framework-4-7-1-asp-net-and-configuration-features/
@vegar @jbogard @danielmarbach @joaomatossilva @fredimachado
There are just two lifetimes that requires a scope in LightInject.
PerRequestLifetime-> new instance for every time it is requested from the container. Tracks disposables that are disposed when the scope ends.PerScopeLifetime-> a single instance per scope. Tracks disposables that are disposed when the scope ends.These lifetimes are used in all types of applications. Web, Console and Desktop apps. You name it.
What changes in between application types is how the scopes are managed. By “managed” I mean how the scopes are stored.
AsyncLocal<T>)So what scope manager should be used for a given application type? Well, it depends 😃
For “legacy” web apps that uses the old
System.Webstack, we can’t really use any of the built-in scope managers. Per thread is not going to work since web requests can start and finish on different threads. Per call context does not really work either since ASP.NET does not flow async locals throughout the web request. The only “safe” place to store ambient informations such as the current scope is in HttpContext.Current.Items collection. It is safe until the point where you do aConfigureAwait(false). That could cause theHttpContext.Currentto returnnulland the ambient information is lost.Take a look here for more information https://github.com/seesharper/LightInject/issues/386
LightInject.Webprovides thePerWebRequestScopeManagerthat stores the scope inHttpContext.Current.Items.For ASP.NET Core applications it is safe to use
PerPerLogicalCallContextScopeManagerProvidersince the entire web request from start to finish in within the same logical call context.My advice is to try to moving the app ASP.NET Core where these are solved properly. You can still target the full framework. Or use
LightInject.Weband be careful with ´ConfigureAwait(false)´.Actually, I do prefer to have it injected where needed rather than have it statictly available everywhere, like in a DbContext.Current way.