zim*_*nen 8 wcf synchronizationcontext
我正在阅读SynchronizationContext并尝试确保OperationContext即使在await通话之后我试图将所有线程都流入所有线程也不会弄乱任何东西.
我有这SynchronizationContext门课:
public class OperationContextSynchronizationContext : SynchronizationContext
{
// Track the context to make sure that it flows through to the next thread.
private readonly OperationContext _context;
public OperationContextSynchronizationContext(OperationContext context)
{
_context = context;
}
public override void Post(SendOrPostCallback d, object state)
{
OperationContext.Current = _context;
d(state);
}
}
Run Code Online (Sandbox Code Playgroud)
然后围绕每个方法调用(使用a Ninject IInterceptor)调用它:
var original = SynchronizationContext.Current;
try
{
// Make sure that the OperationContext flows across to the other threads,
// since we need it for ContextStack. (And also it's cool to have it.)
SynchronizationContext.SetSynchronizationContext(new OperationContextSynchronizationContext(OperationContext.Current));
// Process the method being called.
invocation.Proceed();
}
finally
{
SynchronizationContext.SetSynchronizationContext(original);
}
Run Code Online (Sandbox Code Playgroud)
它似乎工作(我可以根据需要使用OperationContext),但这是正确的方法吗?我错过了一些可能会在以后咬我的重要事项吗?
编辑 Stephen Cleary的一些评论:
public class OperationContextSynchronizationContext : SynchronizationContext, IDisposable
{
// Track the context to make sure that it flows through to the next thread.
private readonly OperationContext _context;
private readonly SynchronizationContext _previous;
public OperationContextSynchronizationContext(OperationContext context)
{
_context = context;
_previous = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(this);
}
public override void Post(SendOrPostCallback d, object state)
{
OperationContext.Current = _context;
d(state);
//(_previous ?? new SynchronizationContext()).Post(d, state);
}
private bool _disposed = false;
public void Dispose()
{
if (!_disposed)
{
SynchronizationContext.SetSynchronizationContext(_previous);
_disposed = true;
}
}
}
Run Code Online (Sandbox Code Playgroud)
最终:
public class OperationContextSynchronizationContext : SynchronizationContext, IDisposable
{
// Track the operation context to make sure that it flows through to the next call context.
private readonly OperationContext _context;
private readonly SynchronizationContext _previous;
public OperationContextSynchronizationContext()
{
_context = OperationContext.Current;
_previous = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(this);
}
public override void Post(SendOrPostCallback d, object state)
{
var context = _previous ?? new SynchronizationContext();
context.Post(
s =>
{
OperationContext.Current = _context;
try
{
d(s);
}
catch (Exception ex)
{
// If we didn't have this, async void would be bad news bears.
// Since async void is "fire and forget," they happen separate
// from the main call stack. We're logging this separately so
// that they don't affect the main call (and it just makes sense).
// log here
}
},
state
);
}
private bool _disposed = false;
public void Dispose()
{
if (!_disposed)
{
// Return to the previous context.
SynchronizationContext.SetSynchronizationContext(_previous);
_disposed = true;
}
}
}
Run Code Online (Sandbox Code Playgroud)
有几件事对我来说很突出。
SynchronizationContext首先,我不建议为此使用 a 。您正在尝试使用框架解决方案解决应用程序问题。会起作用的;我只是从架构的角度来看这是有问题的。不过,唯一的替代方案并不那么干净:可能最合适的方法是编写一个扩展方法,Task返回一个保留OperationContext.
其次,实现OperationContextSynchronizationContext.Post直接执行委托。这有几个问题:一方面,委托应该异步执行(我怀疑 .NET 框架或 TPL 中的一些地方假设了这一点)。另一方面,这SynchronizationContext有一个具体的实现;在我看来,如果自定义 SyncCtx 包装现有的 SyncCtx 会更好。一些 SyncCtx 有特定的线程要求,现在OperationContextSynchronizationContext正在充当这些要求的替代品而不是补充。
第三,自定义SyncCtx在调用其委托时不会将自身设置为当前SyncCtx。await因此,如果同一个方法中有两个 s,它将不起作用。