想尝试将AsyncCTP与TFS一起使用。目前有一个长时间运行的方法,它在TFS查询实例上调用RunQuery。
Query公开了APM方法BeginQuery()和EndQuery()。据我了解,使用AsyncCTP包装这些内容的推荐方法如下:(来自docs的例子)
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);
}
...但是无法编译。得到一个“无效参数”intellisense错误,坦率地说,我无法理解,因为类型和格式看起来是正确的。一个可能的问题可能是Query APM方法期望ICanceleableAsyncResult,而Task工厂期望IAsyncResult - 但是查看TFS API,ICanceleableAsyncResult是IAsyncResult的特化。
不确定我做错了还是不可能。希望能够以AsyncCTP的方式做到这一点,但可能不得不回到APM模式 - 呃!
答案 0 :(得分: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);
}
}