Tôi đang cố gắng tìm ra cách sử dụng tốt nhất lớp HttpClient trong ASP.Net Core.Cách tốt nhất để sử dụng HTTPClient trong ASP.Net Core là DI Singleton
Theo tài liệu và một số bài viết, lớp được khởi tạo tốt nhất một lần trong suốt thời gian tồn tại của ứng dụng và được chia sẻ cho nhiều yêu cầu. Rất tiếc, tôi không thể tìm thấy ví dụ về cách thực hiện chính xác điều này trong Core nên tôi đã đưa ra giải pháp sau.
Nhu cầu cụ thể của tôi yêu cầu sử dụng 2 thiết bị đầu cuối khác nhau (tôi có APIServer cho logic nghiệp vụ và máy chủ định hướng API), vì vậy tôi nghĩ là có 2 bộ đơn HttpClient mà tôi có thể sử dụng trong ứng dụng.
Tôi đã cấu hình servicepoints tôi trong appsettings.json như sau:
"ServicePoints": {
"APIServer": "http://localhost:5001",
"ImageServer": "http://localhost:5002",
}
Tiếp theo, tôi đã tạo ra một HttpClientsFactory rằng sẽ nhanh chóng 2 httpclients của tôi và giữ chúng trong một từ điển tĩnh.
public class HttpClientsFactory : IHttpClientsFactory
{
public static Dictionary<string, HttpClient> HttpClients { get; set; }
private readonly ILogger _logger;
private readonly IOptions<ServerOptions> _serverOptionsAccessor;
public HttpClientsFactory(ILoggerFactory loggerFactory, IOptions<ServerOptions> serverOptionsAccessor) {
_logger = loggerFactory.CreateLogger<HttpClientsFactory>();
_serverOptionsAccessor = serverOptionsAccessor;
HttpClients = new Dictionary<string, HttpClient>();
Initialize();
}
private void Initialize()
{
HttpClient client = new HttpClient();
// ADD imageServer
var imageServer = _serverOptionsAccessor.Value.ImageServer;
client.BaseAddress = new Uri(imageServer);
HttpClients.Add("imageServer", client);
// ADD apiServer
var apiServer = _serverOptionsAccessor.Value.APIServer;
client.BaseAddress = new Uri(apiServer);
HttpClients.Add("apiServer", client);
}
public Dictionary<string, HttpClient> Clients()
{
return HttpClients;
}
public HttpClient Client(string key)
{
return Clients()[key];
}
}
Sau đó, tôi đã tạo giao diện mà tôi có thể sử dụng khi xác định DI sau này. Lưu ý rằng lớp HttpClientsFactory thừa kế từ giao diện này.
public interface IHttpClientsFactory
{
Dictionary<string, HttpClient> Clients();
HttpClient Client(string key);
}
Bây giờ tôi đã sẵn sàng để đưa điều này vào thùng chứa Phụ thuộc của tôi như sau trong lớp Khởi động theo phương pháp ConfigureServices.
// Add httpClient service
services.AddSingleton<IHttpClientsFactory, HttpClientsFactory>();
Tất cả bây giờ được thiết lập để bắt đầu sử dụng điều này trong bộ điều khiển của tôi.
Thứ nhất, tôi nhận sự phụ thuộc. Để làm điều này, tôi đã tạo một thuộc tính lớp riêng để giữ nó, sau đó thêm nó vào chữ ký hàm tạo và kết thúc bằng cách gán đối tượng đến cho thuộc tính lớp cục bộ.
private IHttpClientsFactory _httpClientsFactory;
public AppUsersAdminController(IHttpClientsFactory httpClientsFactory)
{
_httpClientsFactory = httpClientsFactory;
}
Cuối cùng, giờ đây chúng tôi có thể sử dụng Nhà máy để yêu cầu htppclient và thực hiện cuộc gọi. Bên dưới, ví dụ tôi yêu cầu hình ảnh từ máy chủ hình ảnh bằng cách sử dụng httpclientsfactory:
[HttpGet]
public async Task<ActionResult> GetUserPicture(string imgName)
{
// get imageserver uri
var imageServer = _optionsAccessor.Value.ImageServer;
// create path to requested image
var path = imageServer + "/imageuploads/" + imgName;
var client = _httpClientsFactory.Client("imageServer");
byte[] image = await client.GetByteArrayAsync(path);
return base.File(image, "image/jpeg");
}
Xong!
Tôi đã thử nghiệm tính năng này và nó hoạt động tốt trên môi trường phát triển của tôi. Tuy nhiên, tôi không chắc chắn nếu đây là cách tốt nhất để thực hiện điều này. Tôi vẫn còn với các câu hỏi sau:
- Chủ đề giải pháp này có an toàn không? (theo tài liệu MS: ‘Mọi thành viên tĩnh công cộng (Được chia sẻ trong Visual Basic) thuộc loại này đều an toàn.’)
- Thiết lập này có thể xử lý tải nặng mà không cần mở nhiều kết nối riêng biệt không?
- Việc cần làm trong lõi ASP.Net để xử lý sự cố DNS được mô tả trong ‘Singleton HttpClient? Cẩn thận với hành vi nghiêm trọng này và cách khắc phục. ’Tại số http://byterot.blogspot.be/2016/07/singleton-httpclient-dns.html
- Bất kỳ cải tiến hoặc đề xuất nào khác?
cách tiếp cận thú vị, tôi có HttpClient phương pháp tĩnh như một dịch vụ nhưng tôi dint nghĩ về một mô hình nhà máy . Tôi đã tự hỏi phải thử điều này dưới một API yêu cầu xác thực hoặc trường hợp API của bạn là một API mở? Bạn sẽ xử lý như thế nào cho các yêu cầu khác nhau yêu cầu các mã thông báo khác nhau. –
@MuqeetKhan câu trả lời của tôi cho câu hỏi của bạn đã hạ cánh lâu hơn một chút rồi dự đoán. Vì vậy, xin vui lòng tìm thấy nó dưới đây với một ví dụ. – Laobu
Bạn không cần hai phiên bản 'HttpClient'. Chỉ cần đăng ký một singleton và sử dụng nó. Vấn đề DNS sẽ vẫn tồn tại. Là một sidenote, các lớp 'Factory' ** tạo ** một cá thể đối tượng. Đọc thêm về mẫu Nhà máy [tại đây] (https://msdn.microsoft.com/en-us/library/ee817667.aspx). – gldraphael