ASP.Net 코어에서 HttpClient 클래스를 가장 효과적으로 사용하는 방법을 찾으려고합니다.ASP 싱글 코어로 ASP.Net 코어에서 HTTPClient를 사용하는 가장 좋은 방법
문서 및 여러 기사에 따르면 클래스는 응용 프로그램의 수명 동안 한 번만 가장 인스턴스화되고 여러 요청에 대해 공유됩니다. 불행히도 코어에서 올바르게 수행하는 방법의 예제를 찾을 수 없으므로 다음 솔루션을 생각해 냈습니다.
나의 특별한 생각은 응용 프로그램에서 사용할 수있는 2 개의 HttpClient 싱글 톤을 가지고 있기 때문에 두 개의 다른 종단점 (비즈니스 논리와 API 기반 ImageServer 용 APIServer가 있어야 함)을 사용해야한다는 것입니다. 다음과 같이
은 내가 appsettings.json 내 servicepoints을 구성했습니다
"ServicePoints": {
"APIServer": "http://localhost:5001",
"ImageServer": "http://localhost:5002",
}
다음으로, 나는 나의 2 httpclients를 인스턴스화하고 정적 사전에이를 보유 할 HttpClientsFactory를 만들었습니다.
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];
}
}
그런 다음 나중에 DI를 정의 할 때 사용할 수있는 인터페이스를 만들었습니다. HttpClientsFactory 클래스는이 인터페이스를 상속받습니다.
public interface IHttpClientsFactory
{
Dictionary<string, HttpClient> Clients();
HttpClient Client(string key);
}
이제는 ConfigureServices 메소드의 Startup 클래스에서 다음과 같이 이것을 내 종속성 컨테이너에 삽입 할 준비가되었습니다.
// Add httpClient service
services.AddSingleton<IHttpClientsFactory, HttpClientsFactory>();
이제 내 컨트롤러에서 이것을 사용하도록 설정되었습니다.
먼저, 나는 의존성을 도입했습니다. 이렇게하기 위해 private 클래스 속성을 생성 한 다음 생성자 시그니처에 추가하고 들어오는 객체를 로컬 클래스 속성에 할당하여 마칩니다.
private IHttpClientsFactory _httpClientsFactory;
public AppUsersAdminController(IHttpClientsFactory httpClientsFactory)
{
_httpClientsFactory = httpClientsFactory;
}
마지막으로 이제 공장을 사용하여 htppclient를 요청하고 전화를 걸 수 있습니다. 다음은 httpclients 팩터를 사용하는 이미지 서버에서 이미지를 요청하는 예제입니다.
[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");
}
완료!
이 테스트를 거쳤으며 개발 환경에서 훌륭하게 작동합니다. 그러나 이것이 이것을 구현하는 가장 좋은 방법인지 확실하지 않습니다. 다음과 같은 질문을 계속합니다.
- 이 솔루션은 스레드 안전합니까? (MS doc에 따르면 : '이 유형의 공용 static (Visual Basic Basic에서는 Shared) 멤버는 스레드로부터 안전합니다.')
- 이 설정은 많은 개별 연결을 열지 않고도 과중한 부하를 처리 할 수 있습니까?
- 'Singleton HttpClient?'에서 설명한 DNS 문제를 처리하기 위해 ASP.Net 코어에서해야 할 일은 무엇입니까? 이 심각한 행동과 수정 방법에주의하십시오. '위치 : http://byterot.blogspot.be/2016/07/singleton-httpclient-dns.html
- 다른 개선 사항이나 제안이 있습니까?
흥미로운 접근 방식을 업로드하지만 난 공장 패턴을 생각할가 타격을 . 나는 인증을 필요로하는 API 또는 API 케이스가 Open API인지를 알아 내려고 노력해야 할까? 다른 토큰이 필요한 다른 요청에 대해 어떻게 처리 할 것입니까? –
@MuqeetKhan 귀하의 질문에 대한 제 대답은 예상보다 오래 걸렸습니다. 그래서 아래 예제를 통해 찾으십시오. – Laobu
두 개의'HttpClient' 인스턴스가 필요 없습니다. 싱글 톤을 등록하고 사용하십시오. DNS 문제는 여전히 존재합니다. sidenote로서'Factory' 클래스 **는 객체 인스턴스를 생성합니다 **. Factory 패턴에 대한 자세한 내용은 [여기] (https://msdn.microsoft.com/en-us/library/ee817667.aspx)를 참조하십시오. – gldraphael