Chúng tôi đang xây dựng một ứng dụng web đồng thời cao và gần đây chúng tôi đã bắt đầu sử dụng rộng rãi lập trình không đồng bộ (sử dụng TPL và async
/await
).HttpContent.ReadAsStringAsync khiến yêu cầu treo (hoặc các hành vi lạ khác)
Chúng tôi có một môi trường phân tán, trong đó các ứng dụng liên lạc với nhau thông qua các API REST (được xây dựng trên đầu trang của ASP.NET Web API). Trong một ứng dụng cụ thể, chúng tôi có một số DelegatingHandler
sau khi gọi base.SendAsync
(tức là sau khi tính toán phản hồi) ghi lại phản hồi cho tệp. Chúng tôi bao gồm thông tin của phản ứng cơ bản trong nhật ký (mã trạng thái, tiêu đề và nội dung):
public static string SerializeResponse(HttpResponseMessage response)
{
var builder = new StringBuilder();
var content = ReadContentAsString(response.Content);
builder.AppendFormat("HTTP/{0} {1:d} {1}", response.Version.ToString(2), response.StatusCode);
builder.AppendLine();
builder.Append(response.Headers);
if (!string.IsNullOrWhiteSpace(content))
{
builder.Append(response.Content.Headers);
builder.AppendLine();
builder.AppendLine(Beautified(content));
}
return builder.ToString();
}
private static string ReadContentAsString(HttpContent content)
{
return content == null ? null : content.ReadAsStringAsync().Result;
}
Vấn đề là thế này: khi mã đạt content.ReadAsStringAsync().Result
dưới tải máy chủ nặng, yêu cầu đôi khi bị treo trên IIS. Khi nó xảy ra, nó đôi khi trả về một phản ứng - nhưng treo cứng trên IIS như thể nó không - hoặc trong những lúc khác nó không bao giờ trả về.
Tôi cũng đã thử đọc nội dung bằng cách sử dụng ReadAsByteArrayAsync
và sau đó chuyển đổi thành String
, không có may mắn.
Khi tôi chuyển đổi mã để sử dụng async khắp tôi nhận được kết quả thậm chí lạ:
public static async Task<string> SerializeResponseAsync(HttpResponseMessage response)
{
var builder = new StringBuilder();
var content = await ReadContentAsStringAsync(response.Content);
builder.AppendFormat("HTTP/{0} {1:d} {1}", response.Version.ToString(2), response.StatusCode);
builder.AppendLine();
builder.Append(response.Headers);
if (!string.IsNullOrWhiteSpace(content))
{
builder.Append(response.Content.Headers);
builder.AppendLine();
builder.AppendLine(Beautified(content));
}
return builder.ToString();
}
private static Task<string> ReadContentAsStringAsync(HttpContent content)
{
return content == null ? Task.FromResult<string>(null) : content.ReadAsStringAsync();
}
Bây giờ HttpContext.Current
là null sau khi cuộc gọi đến content.ReadAsStringAsync()
, và nó giữ là null cho tất cả các yêu cầu tiếp theo! Tôi biết điều này nghe có vẻ không thể tin được - và nó đã cho tôi một thời gian và sự hiện diện của ba đồng nghiệp để chấp nhận rằng điều này đã thực sự xảy ra.
Đây có phải là hành vi mong đợi không? Tôi có làm gì sai ở đây không?
Bạn nhận ra rằng gọi 'ReadContentAsStringAsync' và sau đó ngay lập tức kêu gọi' Result' trên nó là cơ bản phủ nhận sự không đồng bộ, đúng? Điều đó sẽ chặn cho đến khi công việc đã hoàn thành. Và 'HttpContext.Current' là' null' sau khi âm thanh chờ đợi âm thanh như nó chỉ không chảy qua 'chờ đợi' điểm, đó là irksome nhưng không * hoàn toàn * làm tôi ngạc nhiên. Bạn có thể lấy nó tại * start * của phương thức async của bạn và sau đó sử dụng biến cục bộ đó ... –
Tôi có thể gọi quấn một lượt thử xung quanh một cuộc gọi đến response.EnsureSuccessStatusCode() trước khi thậm chí cố gắng xử lý nội dung. – cgotberg
Bạn có chắc chắn rằng luôn có thể đọc được 'HttpResponseMessage.Content'? Dường như với tôi rằng cố gắng đọc luồng đầu ra của riêng bạn có thể không được hỗ trợ. –