Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C#

Cách consume ASP.NET WebAPI endpoints từ ứng dụng khác dùng C#

Class HttpClient cung cấp base class để gửi/nhận HTTP requests/responses từ URL. Nó hỗ trợ async feature của .NET framework. HttpClient xử lý multiple concurrent requests. Là layer trên HttpWebRequest và HttpWebResponse. Tất cả methods với HttpClient là asynchronous. HttpClient nằm trong namespace System.Net.Http.

Tạo WebAPI application có StudentController và action methods.

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<Student> students = new List<Student> { 
            new Student { Id = 1, Name = "Mark" }, 
            new Student { Id = 2, Name = "John" } 
        }; 
        
        public IEnumerable<Student> Get() { 
            return students; 
        } 
        
        public Student Get(int id) { 
            var studentForId = students.FirstOrDefault(x => x.Id == id); 
            return studentForId; 
        } 
    } 
}

Tạo console application consume WebApi endpoints để lấy student details.

Ví dụ

using System; 
using System.Net.Http; 

namespace DemoApplication { 
    public class Program { 
        static void Main(string[] args) { 
            using (var httpClient = new HttpClient()) { 
                Console.WriteLine("Calling WebApi for get all students"); 
                var students = GetResponse("student"); 
                Console.WriteLine($"All Students: {students}"); 
                
                Console.WriteLine("Calling WebApi for student id 2"); 
                var studentForId = GetResponse("student/2"); 
                Console.WriteLine($"Student for Id 2: {studentForId}"); 
                Console.ReadLine(); 
            } 
        } 
        
        private static string GetResponse(string url) { 
            using (var httpClient = new HttpClient()) { 
                httpClient.BaseAddress = new Uri("https://localhost:58174/api/"); 
                var responseTask = httpClient.GetAsync(url); 
                var result = responseTask.Result; 
                var readTask = result.Content.ReadAsStringAsync(); 
                return readTask.Result; 
            } 
        } 
    } 
}

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"}

Trong ví dụ thấy endpoints WebApi được gọi từ console application riêng biệt.

Best Practices HttpClient

1. Static/Singleton HttpClient (Khuyến nghị)

// Program.cs hoặc Startup.cs
private static readonly HttpClient _httpClient = new HttpClient();

static Program() {
    _httpClient.BaseAddress = new Uri("https://api.example.com/");
    _httpClient.DefaultRequestHeaders.Accept.Add(
        new MediaTypeWithQualityHeaderValue("application/json"));
    _httpClient.Timeout = TimeSpan.FromSeconds(30);
}

// Sử dụng
var response = await _httpClient.GetAsync("api/students");

Lý do: Tránh socket exhaustion do tạo quá nhiều HttpClient instances.

2. IHttpClientFactory (ASP.NET Core 2.1+)

// Startup.cs
services.AddHttpClient("StudentApi", client => {
    client.BaseAddress = new Uri("https://api.example.com/");
    client.DefaultRequestHeaders.Add("Accept", "application/json");
});

// Controller/Service
public class StudentService {
    private readonly IHttpClientFactory _factory;
    
    public StudentService(IHttpClientFactory factory) {
        _factory = factory;
    }
    
    public async Task> GetStudentsAsync() {
        var client = _factory.CreateClient("StudentApi");
        return await client.GetFromJsonAsync>("api/student");
    }
}

3. Typed Client (Strongly typed)

// Interface
public interface IStudentApiClient {
    Task> GetStudentsAsync();
    Task GetStudentAsync(int id);
}

// Implementation
public class StudentApiClient : IStudentApiClient {
    private readonly HttpClient _httpClient;
    
    public StudentApiClient(HttpClient httpClient) {
        _httpClient = httpClient;
    }
    
    public async Task> GetStudentsAsync() 
        => await _httpClient.GetFromJsonAsync>("api/student");
    
    public async Task GetStudentAsync(int id) 
        => await _httpClient.GetFromJsonAsync($"api/student/{id}");
}

// Register
services.AddHttpClient(client => {
    client.BaseAddress = new Uri("https://api.example.com/");
});

4. Polly Policies (Retry, Circuit Breaker, Timeout)

services.AddHttpClient()
    .AddTransientHttpErrorPolicy(p => p.WaitAndRetryAsync(3, _ => TimeSpan.FromSeconds(1)))
    .AddTransientHttpErrorPolicy(p => p.CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)));

Deserialize JSON Response

// System.Text.Json (.NET Core 3.0+)
var students = await response.Content.ReadFromJsonAsync>();

// Newtonsoft.Json
var json = await response.Content.ReadAsStringAsync();
var students = JsonConvert.DeserializeObject>(json);