等待后的AsyncTaskCodeActivity和丢失的上下文

art*_*rek 5 workflow-foundation-4 async-await

在执行第一个await后访问context参数时,AsyncTaskCodeActivity失败.例如:

public class TestAsyncTaskCodeActivity : AsyncTaskCodeActivity<int>
{
    protected async override Task<int> ExecuteAsync(AsyncCodeActivityContext context, CancellationToken cancellationToken)
    {
        await Task.Delay(50);
        // context has already been disposed and the next line throws
        // ObjectDisposedException with the message:
        // An ActivityContext can only be accessed within the scope of the function it was passed into.
        context.Track(new CustomTrackingRecord("test"));
        // more awaits can happen here
        return 3;
    }
}
Run Code Online (Sandbox Code Playgroud)

是否有任何简单的方法来保留上下文,以便在等待之后也可以使用它?

Ste*_*ary 6

啊.

当我写作时AsyncTaskCodeActivity<T>,我假设AsyncCodeActivityContext事实上它在异步方法的开头和结尾都是同一个实例,并且一直可用.事实并非如此(这有点奇怪 - 不确定为什么WF团队做出了这个决定).

取而代之的是,AsyncCodeActivityContext可以在活动的开始和结束访问.确实很尴尬.

下面更新的代码将允许您在开始时访问上下文(例如,读取变量),然后在最后再次访问上下文.我还介绍了一个可选项TState,可用于存储活动状态(活动可以在整个执行过程中访问).请告诉我这是否符合您的需求; 我没有测试过.

public abstract class AsyncTaskCodeActivity<T, TState> : AsyncCodeActivity<T>
{
  protected sealed override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
  {
    TState activityState = PreExecute(context);
    context.UserState = activityState;
    var task = ExecuteAsync(activityState);
    return AsyncFactory<T>.ToBegin(task, callback, state);
  }

  protected sealed override T EndExecute(AsyncCodeActivityContext context, IAsyncResult asyncResult)
  {
    var result = AsyncFactory<T>.ToEnd(asyncResult);
    return PostExecute(context, (TState)context.UserState, result);
  }

  protected virtual TState PreExecute(AsyncCodeActivityContext context)
  {
    return default(TState);
  }
  protected abstract Task<T> ExecuteAsync(TState activityState);
  protected virtual T PostExecute(AsyncCodeActivityContext context, TState activityState, T result)
  {
    return result;
  }
}
public abstract class AsyncTaskCodeActivity<T> : AsyncTaskCodeActivity<T, object>
{
}
Run Code Online (Sandbox Code Playgroud)