异步 QueryQueuedBuilds

Asynchronous QueryQueuedBuilds

我们的程序使用 Microsoft.TeamFoundation.Build.Server 中的 QueryQueuedBuilds 从我们的构建服务器获取所有排队的构建。

到目前为止,我们是通过 DispatcherTimer tick 方法同步的,但 UI 有时会超过 1000 毫秒没有响应。这是原始调用:

    public List<QueuedBuild> GetQueuedBuilds()
    {
        List<QueuedBuild> queuedBuilds = new List<QueuedBuild>();

        foreach (var project in _teamProjectList)
        {
            IQueuedBuildSpec queuedBuildSpec = _buildServer.CreateBuildQueueSpec(project.Name);
            IQueuedBuildQueryResult queuedBuildQueryResult = _buildServer.QueryQueuedBuilds(queuedBuildSpec);

            if (queuedBuildQueryResult.QueuedBuilds.Length > 0)
            {
                foreach (var result in queuedBuildQueryResult.QueuedBuilds)
                {
                    queuedBuilds.Add(new QueuedBuild()
                    {
                     // Set properties from result
                    });
                }
            }                
        }

        return queuedBuilds;
    }

但 QueryQueuedBuilds 的行需要很长时间。

我发现有异步方法 BeginQueryQueuedBuilds 和 EndQueryQueuedBuilds,但我找不到如何使用它的示例。这是我到目前为止得到的:

public List<QueuedBuild> GetQueuedBuilds()
{
    List<QueuedBuild> queuedBuilds = new List<QueuedBuild>();
    Collection<IQueuedBuildSpec> queuedBuildSpecs = new Collection<IQueuedBuildSpec>();

    foreach (var project in _teamProjectList)
    {
        queuedBuildSpecs.Add(_buildServer.CreateBuildQueueSpec(project.Name));
    }

    IAsyncResult asyncResult = _buildServer.BeginQueryQueuedBuilds(queuedBuildSpecs.ToArray(),
        OnBeginQueryQueuedBuilds, queuedBuilds);
    
    // What to do with asyncResult?

    return queuedBuilds; // How to return queuedBuilds?
}

private void OnBeginQueryQueuedBuilds(IAsyncResult ar)
{
    if (!(ar.AsyncState is List<QueuedBuild> queuedBuilds))
    {
        return;
    }

    IQueuedBuildQueryResult[] queryResults = _buildServer.EndQueryQueuedBuilds(ar);

    foreach (var queuedBuildQueryResult in queryResults)
    {
        foreach (var result in queuedBuildQueryResult.QueuedBuilds)
        {
            queuedBuilds.Add(new QueuedBuild()
            {
                // Set properties from result
            });
        }
    }

    // How to get the queuedBuilds back to the GUI?
}

回调方法有效。但是如何让 queuedBuilds 回到我的 GUI?

我终于解决了类似于this解决方案的难题。

我所做的最重要的改变: 不再使用回调方法。 IAsyncResult 现在被传递给 Task.Factory.FromAsync() 方法并等待任务。

这就是我最终得到的结果:

    public async Task<List<QueuedBuild>> GetQueuedBuilds()
    {
        Collection<IQueuedBuildSpec> queuedBuildSpecs = new Collection<IQueuedBuildSpec>();

        foreach (var project in _teamProjectList)
        {
            queuedBuildSpecs.Add(_buildServer.CreateBuildQueueSpec(project.Name));
        }

        IAsyncResult asyncResult = _buildServer.BeginQueryQueuedBuilds(queuedBuildSpecs.ToArray(), null, null);

        var task = Task.Factory.FromAsync(asyncResult, _buildServer.EndQueryQueuedBuilds);
        IQueuedBuildQueryResult[] queuedBuildQueryResults = await task;
        return FinishQueryQueuedBuilds(queuedBuildQueryResults);
    }

    private List<QueuedBuild> FinishQueryQueuedBuilds(IQueuedBuildQueryResult[] queuedBuildQueryResults)
    {
        List<QueuedBuild> queuedBuilds = new List<QueuedBuild>();

        foreach (var queuedBuildQueryResult in queuedBuildQueryResults)
        {
            foreach (var result in queuedBuildQueryResult.QueuedBuilds)
            {
                queuedBuilds.Add(new QueuedBuild()
                {
                    // Set properties from result
                });
            }
        }

        return queuedBuilds;
    }

我希望这可以帮助遇到类似问题的其他人。