Reqnroll (and Specflow v4,x) uses Async internally (only one code path).
To ensure the user sees no difference between the old (synchronous) implementation and the new ones the ExecutionContext (including AsyncLocal) are handled manually by Reqnroll.
This is done using ExecutionContext.Capture() in BindingDelegateInvoker,InvokeInExecutionContext.
The problem is that this only works once.
Background:
In the first call
ExecutionContextHolder.Value is null.
This means that ExecutionContext.Run is not called.
The Binding-Method is called with the current ExecutionContext and modifies the AsyncLocal.
Current ExecutionContext is captured
=> everything is fine.
In the second call
ExecutionContextHolder.Value is not null.
ExecutionContext.Run is called.
ExecutionContext.Run captures the current ExecutionContext
In ExecutionContext.Run the Binding-Method is called and modifies the AsyncLocal.
The ExecutionContext.Run restores the captured "old current" ExecutionContext with the old values
The current (restored) ExecutionContext is captured
=> Information is lost.
Bufix: Capture ExecutionContext explicitly in ExecutionContext.Run after every binding invoke.
Types of changes
[x] Bug fix (non-breaking change which fixes an issue).
[ ] New feature (non-breaking change which adds functionality).
[ ] Breaking change (fix or feature that would cause existing functionality to not work as expected).
[ ] Performance improvement
[ ] Refactoring (so no functional change)
[ ] Other (docs, build config, etc)
Checklist:
[x] I've added tests for my code. (most of the time mandatory)
[x] I have added an entry to the changelog. (mandatory)
[ ] My change requires a change to the documentation.
@obligaron you should be now on the @reqnroll/core-team (you need to accept invitation), so pushing new branches to the main repo should work now. (I hope. Please report if not.)
Fixes #120
Reqnroll (and Specflow v4,x) uses Async internally (only one code path). To ensure the user sees no difference between the old (synchronous) implementation and the new ones the
ExecutionContext
(includingAsyncLocal
) are handled manually by Reqnroll. This is done usingExecutionContext.Capture()
inBindingDelegateInvoker,InvokeInExecutionContext
.The problem is that this only works once. Background:
ExecutionContextHolder.Value
is null.ExecutionContext.Run
is not called.ExecutionContext
and modifies theAsyncLocal
.ExecutionContext
is capturedExecutionContextHolder.Value
is not null.ExecutionContext.Run
is called.ExecutionContext.Run
captures the currentExecutionContext
ExecutionContext.Run
the Binding-Method is called and modifies theAsyncLocal
.ExecutionContext.Run
restores the captured "old current"ExecutionContext
with the old valuesExecutionContext
is capturedBufix: Capture
ExecutionContext
explicitly inExecutionContext.Run
after every binding invoke.Types of changes
Checklist: