7

Chúng tôi đang tạo một trình bao bọc cho HttpClient. Vì chúng tôi sẽ thực hiện theo hướng dẫn tối ưu hóa hiệu suất từ ​​https://github.com/mspnp/performance-optimization. Chúng tôi muốn tránh chống mẫu - Trình bày không đúng cách được đề cập trong tài liệu đó. Tôi đã giới thiệu hướng dẫn này cho nhóm của mình để sử dụng HttpClient tĩnh. Phản hồi tôi nhận được là an toàn chỉ. Mỗi yêu cầu có tiêu đề chứa xác nhận quyền sở hữu của người dùng. Kể từ khi tôi có một HttpClient tĩnh, nó sẽ được thread-an toàn? Nếu chúng ta có nhiều yêu cầu nhấn mã (ví dụ GET) cùng một lúc, nó sẽ là một điều kiện chủng tộc để thiết lập tiêu đề? Chúng tôi đã thực hiện như dưới đây.Tĩnh HttpClient thread an toàn trên ASP.net HttpRequest

public class HttpClientHelper{ 
private static readonly HttpClient _HttpClient; 
static HttpClientHelper() { 
     HttpClient = new HttpClient(); 
     HttpClient.Timeout = TimeSpan.FromMinutes(SOME_CONFIG_VALUE); 
} 

public async Task<HttpResponseMessage> CallHttpClientPostAsync(string requestUri, HttpContent requestBody) 
{ 
    AddHttpRequestHeader(httpClient); 
    var response = await httpClient.PostAsync(requestUri, requestBody); //Potential thread synchronization issue??? 
    return response; 
} 

public HttpResponseMessage CallHttpClientGet(string requestUri) 
{ 
    AddHttpRequestHeader(httpClient); 
    var response = httpClient.GetAsync(requestUri).Result; //Potential thread synchronization issue??? 
    return response; 
} 

private void AddHttpRequestHeader(HttpClient client) 
{ 
    string HeaderName = "CorrelationId"; 
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(Properties.Settings.Default.HttpClientAuthHeaderScheme, GetTokenFromClaims()); //Race condition??? 
    if (client.DefaultRequestHeaders.Contains(HeaderName)) 
     client.DefaultRequestHeaders.Remove(HeaderName); 
    client.DefaultRequestHeaders.Add(HeaderName, Trace.CorrelationManager.ActivityId.ToString()); 
} 

}

+1

Bất kỳ lý do gì mà 'CallHttpClientGet' không đồng bộ? Bằng cách gọi '.Result', bạn đang chặn luồng và mời các deadlocks tiềm ẩn. –

Trả lời

10

Nhóm của bạn là chính xác, đây là xa đề an toàn. Hãy xem xét trường hợp này:

  • Chủ đề A bộ CorrelationId tiêu đề thành "foo".
  • Chủ đề B đặt Tiêu đề CorrelationId thành "bar".
  • Chủ đề A gửi yêu cầu có chứa CorrelationId của chủ đề B.

Phương pháp CallXXX tốt hơn để tạo đối tượng HttpRequestMessage mới và đặt tiêu đề trên các đối tượng đó và sử dụng HttpClient.SendAsync để thực hiện cuộc gọi.

Hãy nhớ rằng việc sử dụng lại HttpClient trường hợp chỉ mang lại lợi ích nếu bạn đang thực hiện nhiều cuộc gọi đến cùng một máy chủ.

+0

"Hãy nhớ rằng việc sử dụng lại các cá thể HttpClient chỉ mang lại lợi ích nếu bạn đang thực hiện nhiều cuộc gọi đến cùng một máy chủ" - bạn có tham chiếu về điều này không? –

+2

@OhadSchneider Nó dựa trên [lời khuyên của Daryl Miller] (https://stackoverflow.com/a/22561368/62600) để sử dụng một ví dụ "cho mỗi API riêng biệt mà bạn kết nối với". Lý do là lợi ích hiệu suất (không phải mở một kết nối mới, vv) chỉ có liên quan trên mỗi máy chủ, như là một số thuộc tính HttpClient nhất định như DefatultHeaders. Tuy nhiên, vấn đề ổ cắm [nổi tiếng] hiện nay (https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/) có thể thay đổi lời khuyên của tôi một chút. Windows có thể lấy lại một socket trong TIME_WAIT để sử dụng với một máy chủ khác không? Tôi không chắc. Tôi đã đăng câu hỏi trên bài viết đó. –

Các vấn đề liên quan