1

想尝试将 AsyncCTP 与 TFS 一起使用。当前有一个长时间运行的方法,它在 TFS 查询实例上调用 RunQuery。

Query 公开了 APM 方法 BeginQuery() 和 EndQuery()。据我了解,使用 AsyncCTP 包装这些内容的推荐方法类似于:(来自文档的示例)

Task<int>.Factory.FromAsync(stream.BeginRead, stream.EndRead, buffer, offset, count, null);

此外,将其包装在文档中的扩展方法中,因此我的实际方法如下所示:

public static Task<WorkItemCollection> RunQueryAsync(this Query query)
{
    if (query== null) 
        throw new ArgumentNullException("Query");

    return Task<WorkItemCollection>.Factory.FromAsync(query.BeginQuery, query.EndQuery, null);
} 

...但这无法编译。得到一个“无效参数”智能感知错误,坦率地说,我无法真正理解,因为类型和格式看起来是正确的。一个可能的问题是 Query APM 方法需要一个 ICanceleableAsyncResult,而任务工厂需要一个 IAsyncResult ——但是从 TFS API 来看,ICanceleableAsyncResult 是 IAsyncResult 的一种特化。

不知道我做错了还是不可能。希望能够以 AsyncCTP 方式实现,但可能不得不回到 APM 模式——呃!

4

1 回答 1

4

更新:我的Nito.AsyncEx库现在包含一个TeamFoundationClientAsyncFactory类型,可以使用它而不是在下面滚动您自己的实现。


TFS API 没有严格遵循 APM 模式,因为它不带state参数,这会阻止内置函数TaskFactory.FromAsync工作。

您必须编写自己的FromAsync等价物,可以使用TaskCompletionSource

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.TeamFoundation.Client;

public static class TfsUtils<TResult>
{
  public static Task<TResult> FromTfsApm(Func<AsyncCallback, ICancelableAsyncResult> beginMethod, Func<ICancelableAsyncResult, TResult> endMethod, CancellationToken token)
  {
    // Represent the asynchronous operation by a manually-controlled task.
    TaskCompletionSource<TResult> tcs = new TaskCompletionSource<TResult>();
    try
    {
      // Begin the TFS asynchronous operation.
      var asyncResult = beginMethod(Callback(endMethod, tcs));

      // If our CancellationToken is signalled, cancel the TFS operation.
      token.Register(asyncResult.Cancel, false);
    }
    catch (Exception ex)
    {
      // If there is any error starting the TFS operation, pass it to the task.
      tcs.TrySetException(ex);
    }

    // Return the manually-controlled task.
    return tcs.Task;
  }

  private static AsyncCallback Callback(Func<ICancelableAsyncResult, TResult> endMethod, TaskCompletionSource<TResult> tcs)
  {
    // This delegate will be invoked when the TFS operation completes.
    return asyncResult =>
    {
      var cancelableAsyncResult = (ICancelableAsyncResult)asyncResult;

      // First check if we were canceled, and cancel our task if we were.
      if (cancelableAsyncResult.IsCanceled)
        tcs.TrySetCanceled();
      else
      {
        try
        {
          // Call the TFS End* method to get the result, and place it in the task.
          tcs.TrySetResult(endMethod(cancelableAsyncResult));
        }
        catch (Exception ex)
        {
          // Place the TFS operation error in the task.
          tcs.TrySetException(ex);
        }
      }
    };
  }
}

然后,您可以在扩展方法中使用它,如下所示:

using System.Threading;
using System.Threading.Tasks;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

public static class TfsExtensions
{
  public static Task<WorkItemCollection> QueryAsync(this Query query, CancellationToken token = new CancellationToken())
  {
    return TfsUtils<WorkItemCollection>.FromTfsApm(query.BeginQuery, query.EndQuery, token);
  }
}
于 2011-09-22T16:46:08.897 回答