Как правильно дождаться завершения задачи?
Помогите разобраться, есть такой код:
foreach (var advert in rtb_partners)
{
if (advert == null)
throw new Exception("Dsp not found");
var protocol = advert.Protocol;
if (protocol != RtbProtocolEnum.OpenRTB_2_2 &&
protocol != RtbProtocolEnum.OpenRTB_2_3 &&
protocol != RtbProtocolEnum.OpenRTB_2_4 &&
protocol != RtbProtocolEnum.OpenRTB_2_5)
throw new Exception("RTB protocol not supported");
bids[i] = ProcessBidRequest(bidRequest, advert.Endpoint, protocol);
i++;
}
Тут все стандартно, внутри foreach вызывается метод ProcessBidRequest(), вот его код
public async Task<AuctionRequest> ProcessBidRequest(BidRequestModel requestModel, string endpoint, RtbProtocolEnum protocol)
{
try
{
var requestString = JsonConvert.SerializeObject(requestModel);
string address = @"http://192.168.56.1:8000/response.json";
var request = new HttpRequestMessage(HttpMethod.Get, address);
request.Content = new StringContent(requestString);
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
switch (protocol)
{
case RtbProtocolEnum.OpenRTB_2_2:
request.Headers.Add("x-openrtb-version", "2.2");
break;
case RtbProtocolEnum.OpenRTB_2_3:
request.Headers.Add("x-openrtb-version", "2.3");
break;
case RtbProtocolEnum.OpenRTB_2_4:
request.Headers.Add("x-openrtb-version", "2.4");
break;
case RtbProtocolEnum.OpenRTB_2_5:
request.Headers.Add("x-openrtb-version", "2.5");
break;
}
using (var response = await _client.SendAsync(request))
{
var respString = await response.Content.ReadAsStringAsync();
if (response.StatusCode != HttpStatusCode.NoContent && response.StatusCode != HttpStatusCode.OK)
throw new BadResponseException(response.ReasonPhrase);
if (string.IsNullOrEmpty(respString))
throw new ArgumentException("The value is null.");
return new AuctionRequest(requestModel, JsonConvert.DeserializeObject<BidResponseModel>(respString), protocol);
}
}
catch (Exception ex)
{
_logger.LogWarning(ex.Message);
throw ex;
}
}
Когда debug доходит до этой строки "using (var response = await _client.SendAsync(request))", то выполнение возвращается обратно в цикл foreach и получается, что я не могу прочитать содержимое первой итерации, можно это как нибудь исправить?
P.S. Вторая итерация проходит нормально и результат удается прочитать
Ответы (1 шт):
Автор решения: aepot
→ Ссылка
Во-первых, неплохо бы причесать код асинхронного метода
public async Task<AuctionRequest> ProcessBidRequest(BidRequestModel requestModel, string endpoint, RtbProtocolEnum protocol)
{
try
{
string protocolVersion = protocol switch
{
RtbProtocolEnum.OpenRTB_2_2 => "2.2",
RtbProtocolEnum.OpenRTB_2_3 => "2.3",
RtbProtocolEnum.OpenRTB_2_4 => "2.4",
RtbProtocolEnum.OpenRTB_2_5 => "2.5",
_ => throw new NotSupportedException("RTB protocol not supported")
};
var requestString = JsonConvert.SerializeObject(requestModel);
string address = @"http://192.168.56.1:8000/response.json";
using var request = new HttpRequestMessage(HttpMethod.Get, address)
{
Content = new StringContent(requestString, Encoding.UTF8, "application/json");
};
request.Headers.Add("x-openrtb-version", protocolVersion);
using var response = await _client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
if (!response.IsSuccessStatusCode)
throw new BadResponseException(response.ReasonPhrase);
// можно еще так без условия response.EnsureSuccessStatusCode();
var respString = await response.Content.ReadAsStringAsync();
if (respString.Length == 0)
throw new ArgumentException("The response is empty string.");
return new AuctionRequest(requestModel, JsonConvert.DeserializeObject<BidResponseModel>(respString), protocol);
}
catch (Exception ex)
{
_logger.LogWarning(ex.Message);
ExceptionDispatchInfo.Capture(ex).Throw(); // сохранить оригинальный Stack Trace
throw;
}
}
Во-вторых, чтобы дождаться асинхронную операцию, надо использовать await
foreach (var advert in rtb_partners)
{
if (advert == null)
throw new ArgumentNullException(nameof(advert), "Dsp not found");
bids[i++] = await ProcessBidRequest(bidRequest, advert.Endpoint, advert.Protocol);
}
Если хочется распараллелить асинхронные операции, то можно так:
List<Task<AuctionRequest>> tasks = new List<Task<AuctionRequest>>();
foreach (var advert in rtb_partners)
{
if (advert == null)
throw new ArgumentNullException(nameof(advert), "Dsp not found");
tasks.Add(ProcessBidRequest(bidRequest, advert.Endpoint, advert.Protocol));
}
AuctionRequest[] bids = await Task.WhenAll(tasks);