Асинхронные множественные запросы веб-службы с упорядоченным результатом - PullRequest
0 голосов
/ 06 июля 2018

Учитывая определенное количество объектов запроса (макс. 9), мне нужно вызывать конечную точку веб-службы одинаковое количество раз асинхронно. С .NET 4.0 мы использовали delegate и IAsyncResult для достижения этой цели.

Есть ли лучший способ сделать это с asyc/await, TPL или с обоими в сочетании с .NET 4.6.1?

Будет ли использование Parallel.ForEach с ConcurrentBag оптимальным, как предложено в этом ответе ?

Пример синхронного кода:

public List<WbsResponse> GetWbsResults()
{
    List<WbsRequest> requests = CompileWbsRequests();
    List<WbsResponse> results = new List<WbsResponse>();
    foreach (var request in requests)
    {
        //Call same web service endpoint n number of times
        var response = CallWebService(request);
        results.Add(response);
    }

    //do something with results

    return results;
}

private WbsResponse CallWebService(WbsRequest request)
{
    //Call web service
}

Редактировать / обновить 1 : На основе ответа @ Thierry я создал пример кода, предполагая, что в объектах запроса и ответа есть свойство Order для пометки порядка запроса / ответа:

public List<WbsResponse> GetWbsResults()    
{        
    List<WbsRequest> requests = CompileWbsRequests();
    List<WbsResponse> results = new List<WbsResponse>();

    Parallel.ForEach(requests, (request) => {
        var response = CallWebService(request);
        response.Order = request.Order;
        results.Add(response);
    });

    results = results.OrderBy(r => r.Order).ToList();

    //do something with results

    return results;
}

private WbsResponse CallWebService(WbsRequest request)
{
    //Call web service
}

Редактировать / обновить 2 : На основе этой темы я внес несколько изменений в Обновление 1:

await Task.Run(() => {
    Parallel.ForEach(requests, (request) => {
        var response = CallWebService(request);
        response.Order = request.Order;
        results.Add(response);
    });
});

Сводка требований:

  • Выполнение нескольких запросов веб-службы асинхронно к одной и той же конечной точке с разными параметрами.
  • Добавление результатов веб-службы в список в том же порядке, в котором был сделан запрос (как если бы он был синхронным).

Ответы [ 2 ]

0 голосов
/ 06 июля 2018

Поскольку каждая задача заканчивается с разным моментом, я думаю, что вы должны пронумеровать запрос и упорядочить ответы по этой нумерации.

В запросе вы инициализируете цифру и пропускаете эту цифру для связанного ответа.Наконец, когда у меня есть результаты, я заказываю их.Как это:

    public async Task<List<WbsResponse>> GetWbsResults()
    {
        List<WbsRequest> requests = CompileWbsRequests();
        List<Task<WbsResponse>> tasks = new List<Task<WbsResponse>>();
        for (var i = 0; i < requests.Count; i++)
        {
            var task = new Task<WbsResponse>(() => { CallWebService(WbsRequest); });
            tasks.Add(task);
        }
        var responses = await Task.WhenAll(tasks);

        var responsesOrdered = responses.OrderBy(r => r.Order)

        //do something with results

        return results;
    }  



    public List<WbsRequest> CompileWbsRequests()
    {
        //create requests
        foreach(var request in requests)
        {
            request.Order += 1;
        }
    }


    private WbsResponse CallWebService(WbsRequest request)
    {
        //Call web service

        reponse.order = request.order;
        return reponse;
    }
0 голосов
/ 06 июля 2018

Я думаю, вы можете использовать Task.WaitAll, чтобы заставить код работать асинхронно, и он будет выглядеть также красивее:

public List<WbsResponse> GetWbsResults()
{
    List<WbsRequest> requests = CompileWbsRequests();
    var responses = await Task.WhenAll(requests.Select(CallWebService));
    return responses;
}

но вы должны изменить этот метод, как показано ниже, чтобы вернуть задачу:

private async Task<WbsResponse> CallWebService(WbsRequest request)
{
    //Call web service
}
...