As Stephen Toub explained in this post, when you submit a message to an ActionBlock, you can ExecutionContext.Capture before calling ActionBlock.Post, pass a DTO holding both message and ExecutionContext into the block, then inside the message handling delegate use ExecutionContext.Run to run the delegate on the captured context:
public sealed class ContextFlowProcessor<T> {
private struct MessageState {
internal ExecutionContext Context;
internal T Value;
}
private readonly ITargetBlock<MessageState> m_block;
public ContextFlowProcessor(Action<T> action) {
m_block = new ActionBlock<MessageState>(ms =>
{
if (ms.Context != null)
using (ms.Context) ExecutionContext.Run(ms.Context, s => action((T)s), ms.Value);
else
action(ms.Value);
});
}
public bool Post(T item) {
var ec = ExecutionContext.Capture();
var rv = m_block.Post(new MessageState { Context = ec, Value = item });
if (!rv) ec.Dispose();
return rv;
}
public void Done() { m_block.DeclinePermanently(); }
public Task CompletionTask { get { return m_block.CompletionTask; } }
This works well when the logic inside the message handler is synchronous. But how can I run a piece of async logic on the captured ExecutionContext? I need something like this:
m_block = new ActionBlock<MessageState>(async ms =>
{
// omitting the null context situation for brevity
using (ms.Context)
{
await ExecutionContext.Run(ms.Context, async _ => { callSomethingAsync(ms.Value) });
}
});
Obviously, this doesn't compile because ExecutionContext.Run does not support asynchronous delegates (while ActionBlock does) - so how can I do this?
DeclinePermanently
, propertyCompletionTask
). So the information provided my not be accurate. My experiments indicate that theExecutionContext
is captured by default, and theContextFlowProcessor
behaves the same as a simpleActionBlock
. Do you have an example that shows a difference? – Shovelboardasync/await
keywords are usingExecutionContext
behind the scenes.Theasync/await
is just some infrastructure that help simulate synchronous semantics in asynchronous programing. so when you are usingExecutionContext
it means you gonna handle things manually. and i think it doesn't make sense toExecutionContext.Run
supportasync/await
while they are themselves based onExecutionContext.Run
and they are using it – Ceram