คลาส HttpClient จัดเตรียม Base Class สำหรับส่ง/รับ HTTP Requests/Responses จาก URL รองรับ Async Feature ของ .NET Framework HttpClient สามารถประมวลผล Multiple Concurrent Requests ได้ เป็น Layer บน HttpWebRequest และ HttpWebResponse ทุก Method ของ HttpClient เป็น Asynchronous HttpClient อยู่ใน Namespace System.Net.Http
สร้าง Web API Application (Server)
// Student Model
namespace DemoWebApplication.Models {
public class Student {
public int Id { get; set; }
public string Name { get; set; }
}
}
// Student Controller
using DemoWebApplication.Models;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace DemoWebApplication.Controllers {
public class StudentController : ApiController {
List students = new List {
new Student { Id = 1, Name = "Mark" },
new Student { Id = 2, Name = "John" }
};
public IEnumerable Get() {
return students;
}
public Student Get(int id) {
var studentForId = students.FirstOrDefault(x => x.Id == id);
return studentForId;
}
}
}
สร้าง Console Application (Client) เพื่อ Consume API
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace DemoApplication {
public class Program {
static async Task Main(string[] args) {
using (var httpClient = new HttpClient()) {
httpClient.BaseAddress = new Uri("https://localhost:58174/api/");
Console.WriteLine("Calling WebAPI for get all students");
var students = await GetResponseAsync(httpClient, "student");
Console.WriteLine($"All Students: {students}");
Console.WriteLine("Calling WebAPI for student id 2");
var studentForId = await GetResponseAsync(httpClient, "student/2");
Console.WriteLine($"Student for Id 2: {studentForId}");
Console.ReadLine();
}
}
private static async Task GetResponseAsync(HttpClient httpClient, string url) {
var response = await httpClient.GetAsync(url);
response.EnsureSuccessStatusCode(); // Throw ถ้าไม่ใช่ 2xx
return await response.Content.ReadAsStringAsync();
}
}
}
Output
Calling WebAPI for get all students
All Students: [{"Id":1,"Name":"Mark"},{"Id":2,"Name":"John"}]
Calling WebAPI for student id 2
Student for Id 2: {"Id":2,"Name":"John"}
Best Practices สำหรับ HttpClient
1. ใช้ IHttpClientFactory (แนะนำใน .NET Core / .NET 5+)
// Startup.cs
services.AddHttpClient("StudentApi", client => {
client.BaseAddress = new Uri("https://localhost:58174/api/");
client.DefaultRequestHeaders.Add("Accept", "application/json");
});
// ใน Service/Controller
public class StudentService {
private readonly HttpClient _httpClient;
public StudentService(IHttpClientFactory factory) {
_httpClient = factory.CreateClient("StudentApi");
}
public async Task> GetAllAsync() {
var response = await _httpClient.GetAsync("student");
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync>();
}
}
2. ใช้ ReadFromJsonAsync (System.Net.Http.Json)
using System.Net.Http.Json;
var students = await httpClient.GetFromJsonAsync>("student");
var student = await httpClient.GetFromJsonAsync("student/2");
3. จัดการ HttpClient Lifetime ให้ถูกต้อง
- ไม่ควร สร้าง `new HttpClient()` ทุกครั้งใน Loop (Socket Exhaustion)
- ควร ใช้ Singleton หรือ IHttpClientFactory
- ควร ใช้ `using` สำหรับ Request/Response แต่ไม่ใช่ HttpClient เอง
4. Polly สำหรับ Retry และ Circuit Breaker
services.AddHttpClient("StudentApi")
.AddTransientHttpErrorPolicy(p => p.WaitAndRetryAsync(3, _ => TimeSpan.FromSeconds(1)))
.AddTransientHttpErrorPolicy(p => p.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)));
การ Deserialize JSON Response
// ใช้ System.Text.Json (Built-in .NET Core 3.0+)
using System.Text.Json;
var json = await response.Content.ReadAsStringAsync();
var students = JsonSerializer.Deserialize>(json, new JsonSerializerOptions {
PropertyNameCaseInsensitive = true
});
// หรือ Newtonsoft.Json (Json.NET)
using Newtonsoft.Json;
var students = JsonConvert.DeserializeObject>(json);