C# Cơ bản .NET Core §1) Cài đặt, chương trình C# đầu tiên §2) Biến, kiểu dữ liệu và nhập/xuất §3) Toán tử số học và gán §4) So sánh, logic và lệnh if, switch §5) Vòng lặp for, while §6) Phương thức - Method §7) Phương thức - Delegate §8) Lớp - Class §9) Kiểu vô danh và dynamic §10) Biểu thức lambda §11) Event §12) Hàm hủy - Quá tải toán tử - thành viên tĩnh - indexer §13) Lớp lồng nhau - namespace §14) null và nullable §15) Mảng §16) Chuỗi ký tự §17) Tính kế thừa §18) Tính đa hình - abstract - interface §19) Struct và Enum §20) Ngoại lệ Exeption §21) IDisposable - using §22) File cơ bản §23) FileStream §24) Generic §25) Collection - List §26) SortedList §27) Queue / Stack §28) Linkedlist §29) Dictionary - HashSet §30) Phương thức mở rộng §31) ObservableCollection §32) LINQ §33) (Multithreading) async - bất đồng bộ §34) Type §35) Attribute Annotation §36) DI Dependency Injection §37) (Multithreading) Parallel §38) (Networking) HttpClient §39) (Networking) HttpMessageHandler §40) (Networking) HttpListener §41) (Networking) Tcp TcpListenerr/TcpClient §42) (ADO.NET) SqlConnection §43) (ADO.NET) SqlCommand §44) (EF Core) Tổng quan §45) (EF Core) Tạo Model §46) (EF Core) Fluent API §47) (EF Core) Query §48) (EF Core) Scaffold §49) (EF Core) Migration §50) (ASP.NET CORE) Hello World! §51) (ASP.NET CORE) Middleware §52) (ASP.NET CORE) Map - Request - Response §53) (ASP.NET CORE) IServiceCollection - MapWhen §54) (ASP.NET CORE) Session - ISession §55) (ASP.NET CORE) Configuration §56) (ASP.NET CORE MVC) Controller - View
Lập trình C# (C Sharp)

Lớp HttpMessageHandler

Lớp HttpMessageHandler là lớp trừu tượng, nó được thư viện .NET Corre triển khai ra các lớp có chức năng nhận các yêu cầu request (HttpRequestMessage) gửi đến và trả về respone (HttpResponseMessage).

Các lớp triển khai từ lớp này như DelegatingHandler, HttpClientHandler, SocketsHttpHandler, chúng overrrid phương thức SendAsync, ở đây ta chỉ sử dụng các lớp triển khai này
protected Task<HttpResponseMessage> SendAsync (HttpRequestMessage request, CancellationToken cancellationToken);

Các HttpMessageHandler có thể áp dụng ở phía server hoặc client - ở đây ta sẽ áp dụng chúng ở client, cụ thể là thiết lập cho lớp HttpClient mà ta đã tìm hiểu chúng ở phần trước. Khi đó mỗi khi HttpClient thực hiện SendAsync nó sẽ triệu gọi đến SendAsync của handler. Mục đích để thiết lập thêm các request và respone khi kết nối.

Chú ý, từ .NET Core 2.1 khuyến khích sử dụng SocketsHttpHandler thay cho HttpClientHandler. Giờ ta sẽ tìm hiểu các handler trên.

Sử dụng HttpClientHandler cho HttpClient

Bạn có thể tạo một đối tượng HttpClientHandler bằng toán tử new, hoặc tạo lớp kế thừa nó, sau đó thiết lập các thuộc tính cần thiết. Đối tượng này Inject vào HttpClient bằng phương thức khởi tạo. Khi đó, mỗi khi HttpClient thực hiện SendAsync nó sẽ tham chiếu gọi đến SendAsync của handler.

Một số thuộc tính trong HttpClientHandler

Thuộc tính Mô tả
AllowAutoRedirect Thuộc tính, mặc định là true, để thiết lập tự động chuyển hướng. Ví dụ truy vấn đến URI có chuyển hướng đến đích mới (301) thì - HttpClient sẽ tự động chuyển hướng truy vấn đến đó.
AutomaticDecompression Thuộc tính thuộc tính để handler tự động giải nén / nén nội dung HTTP, nó thuộc kiểu enum DecompressionMethods gồm có:
  • DecompressionMethods.None không sử dụng nén
  • DecompressionMethods.GZip dùng thuật toán gZip
  • DecompressionMethods.Deflate dùng thuật toán nén deflate

Ví dụ có thể gán:

AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip
UseCookies Mặc định là true: cho phép sử dụng thuộc tính CookieContainer để lưu các Cookie của server khi respone trả về, cũng như tự động gửi Cookie khi gửi truy vấn
CookieContainer Thuộc tính thuộc lớp CookieContainer, nó lưu các cookie.

Ví dụ sau, triển khai một lớp tên MyHttpClientHandler, kế thừa HttpClientHandler, handler này sử dụng ContainerCookie riêng để lưu cookie ...

Source Code

static CookieContainer cookieContainer = new CookieContainer();  // Sử dụng CookieContainer riêng, để lưu lại Cookie - hoặc thêm cookie

public class MyHttpClientHandler : HttpClientHandler { public MyHttpClientHandler(CookieContainer cookie_container) { CookieContainer = cookie_container; // Thay thế CookieContainer mặc định AllowAutoRedirect = false; // không cho tự động Redirect AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip; UseCookies = true; } protected override async Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { ShowHeaders("Request header trước khi qua Handler ", request.Headers); var task = base.SendAsync(request, cancellationToken); // bắt buộc gọi await task; ShowHeaders("Request header sau khi qua Handler ", request.Headers); // // Xem Cookie nếu có // var uri = request.RequestUri; // var cookieHeader = CookieContainer.GetCookieHeader(uri); // Console.WriteLine(cookieHeader); return task.Result; } }
// Chức năng in thông tin Header public static void ShowHeaders(string lable, HttpHeaders headers) { Console.WriteLine(lable); foreach (var header in headers) { string value = string.Join(" ", header.Value); Console.WriteLine($"{header.Key,20} : {value}"); } Console.WriteLine(); } public static async Task<string> GetWebContent(string url) { using (var myHttpClientHandler = new MyHttpClientHandler(cookieContainer)) using (var httpClient = new HttpClient(myHttpClientHandler)) { Console.WriteLine($"Starting connect {url}"); httpClient.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml+json"); httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36"); HttpResponseMessage response = await httpClient.GetAsync(url); response.EnsureSuccessStatusCode(); string htmltext = await response.Content.ReadAsStringAsync(); return htmltext; } } static void Main(string[] args) { string url = "https://www.google.com.vn/"; cookieContainer.Add(new Uri(url), new Cookie("NameCookie", "ValueCookie")); // Thêm Cookie khi gửi Requests var htmltask = GetWebContent(url); htmltask.Wait(); // cho hoàn thành tác vụ var html = htmltask.Result; // đọc chuỗi trả về (content) Console.WriteLine(html!=null ? html.Substring(0, 150): "Lỗi"); }

Sử dụng SocketsHttpHandler cho HttpClient

Lớp handler SocketsHttpHandler sử dụng giống hệt HttpClientHandler tuy nhiên nó là lớp sealed nên không triển khai lớp từ nó, nó có các thuộc tính tương tự HttpClientHandler, tuy nhiên nó được thiết kế để sử dụng tốt hơn - nhanh hơn trên .NET Core, nó độc lập thiết bị tốt hơn (chạy tốt trên macOS, Linux).

Ví dụ: Mã nguồn sử dụng SocketsHttpHandler


static CookieContainer cookieContainer = new CookieContainer();  // Sử dụng CookieContainer riêng, để lưu lại Cookie - hoặc thêm cookie

public static async Task<string> GetWebContent(string url)
{
    using (var socketsHandler = new SocketsHttpHandler())
    {
        socketsHandler.CookieContainer         = cookieContainer;     // Thay thế CookieContainer mặc định
        socketsHandler.AllowAutoRedirect       = false;                // không cho tự động Redirect
        socketsHandler.AutomaticDecompression  = DecompressionMethods.Deflate | DecompressionMethods.GZip;
        socketsHandler.UseCookies              = true;


        using (var httpClient = new  HttpClient(socketsHandler))
        {

            Console.WriteLine($"Starting connect {url}");
            httpClient.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml+json");
            httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36");
            HttpResponseMessage response = await httpClient.GetAsync(url);
            response.EnsureSuccessStatusCode();
            string htmltext = await response.Content.ReadAsStringAsync();
            return htmltext;
        }
    }
}

static void Main(string[] args)
{
    string url = "https://www.google.com.vn/";

    cookieContainer.Add(new Uri(url), new Cookie("NameCookie", "ValueCookie"));     // Thêm Cookie khi gửi Requests

    var htmltask = GetWebContent(url);
    htmltask.Wait();                                                                // cho hoàn thành tác vụ
    var html = htmltask.Result;                                                     // đọc chuỗi trả về (content)
    Console.WriteLine(html!=null ? html.Substring(0, 150): "Lỗi");

    Console.WriteLine();
    Console.WriteLine("Cookie Header:");
    Console.WriteLine(cookieContainer.GetCookieHeader(new Uri(url)));
}

Sử dụng DelegatingHandler cho HttpClient

DelegatingHandler (cũng triển khải từ HttpMessageHandler) là một handler đặc biệt, nó như một MiddleWare để tạo ra một pipeline. Mỗi đối tượng DelegatingHandler có một thuộc tính InnerHandler (kiểu HttpMessageHandler), phải được gán bằng một đối tượng SocketsHttpHandler, HttpClientHandler hoặc DelegatingHandler. Có thể thiết lập InnerHandler qua phương thức khởi tạo lớp.

Đối với loại handler này, request - respone sẽ đi qua nó, sau đó đi qua handler thiết lập ở thuộc tính InnerHandler, cứ như vậy bạn có thể tạo ra chuỗi các handler mà request/response phải đi qua.

Ví dụ:

1 Sử dụng lại lớp MyHttpClientHandler triển khai từ HttpClientHandler của ví dụ ở trên.

2 Tạo một lớp handler có tên DenyAccessFacebook triển khai từ DelegatingHandler, mục đích để cấm truy cập facebook.com


public class DenyAccessFacebook : DelegatingHandler
{
    public DenyAccessFacebook(HttpMessageHandler innerHandler) : base(innerHandler) { }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var host = request.RequestUri.Host.ToLower();
        Console.WriteLine($"Check in  DenyAccessFacebook - {host}");
        if (host.Contains("facebook.com"))
        {
            var response = new HttpResponseMessage(HttpStatusCode.OK);
            response.Content  = new ByteArrayContent(Encoding.UTF8.GetBytes("Không được truy cập"));
            return Task.FromResult<HttpResponseMessage>(response);
        }

        return base.SendAsync(request, cancellationToken);
    }
}

3 Tương tự, tạo một lớp handler có tên ChangeUri, nếu truy cập google.com sẽ chuyển thành truy cập github.com

4 Cuối cùng, tạo ra pipleline sau:

var myHttpClientHandler = new MyHttpClientHandler(cookieContainer);
var changeUri           = new ChangeUri(myHttpClientHandler);
var facebookHandler     = new DenyAccessFacebook(changeUri);

Như vậy, nếu dùng facebookHandler cho HttpClient thì request/response sẽ đi qua facebookHander sau đó đi qua changeUri, cuối cùng là myHttpClientHandler

Áp dụng: Source Code


static CookieContainer cookieContainer = new CookieContainer();

public class ChangeUri : DelegatingHandler
{
    public ChangeUri(HttpMessageHandler innerHandler) : base(innerHandler) {}

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var host = request.RequestUri.Host.ToLower();
        Console.WriteLine($"Check in  ChangeUri - {host}");
        if (host.Contains("google.com"))
        {
            request.RequestUri = new Uri("https://github.com/");
        }

        return base.SendAsync(request, cancellationToken);
    }
}
public class DenyAccessFacebook : DelegatingHandler
{
    public DenyAccessFacebook(HttpMessageHandler innerHandler) : base(innerHandler)
    {
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {

        var host = request.RequestUri.Host.ToLower();
        Console.WriteLine($"Check in  DenyAccessFacebook - {host}");
        if (host.Contains("facebook.com"))
        {
            var response = new HttpResponseMessage(HttpStatusCode.OK);
            response.Content  = new ByteArrayContent(Encoding.UTF8.GetBytes("Không được truy cập"));
            return Task.FromResult<HttpResponseMessage>(response);
        }

        return base.SendAsync(request, cancellationToken);
    }
}


public class MyHttpClientHandler : HttpClientHandler {
    public MyHttpClientHandler(CookieContainer  cookie_container) {

        CookieContainer         = cookie_container;     // Thay thế CookieContainer mặc định
        AllowAutoRedirect       = false;                // không cho tự động Redirect
        AutomaticDecompression  = DecompressionMethods.Deflate | DecompressionMethods.GZip;
        UseCookies              = true;
    }

    protected override async Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken)
    {
        ShowHeaders("Request header trước khi qua Handler MyHttpClientHandler", request.Headers);

        var task  = base.SendAsync(request, cancellationToken); // bắt buộc gọi
        await task;

        ShowHeaders("Request header sau khi qua Handler MyHttpClientHandler", request.Headers);


        return task.Result;
    }
}


// Chức năng in thông tin Header
public static void ShowHeaders(string lable, HttpHeaders headers)
{
    Console.WriteLine(lable);
    foreach (var header in headers)
    {
        string value = string.Join(" ", header.Value);
        Console.WriteLine($"{header.Key,20} : {value}");
    }
    Console.WriteLine();

 }


public static async Task<string> GetWebContent(string url)
{
    //  Midleware Pipeline:
    //  facebookHandler -- changeUri -- myHttpClientHandler

    using (var myHttpClientHandler = new MyHttpClientHandler(cookieContainer))
    using (var changeUri  = new ChangeUri(myHttpClientHandler))
    using (var facebookHandler  = new DenyAccessFacebook(changeUri))

    using (var httpClient = new  HttpClient(facebookHandler))
    {

        Console.WriteLine($"Starting connect {url}");
        httpClient.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml+json");
        httpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36");
        HttpResponseMessage response = await httpClient.GetAsync(url);
        response.EnsureSuccessStatusCode();
        string htmltext = await response.Content.ReadAsStringAsync();
        return htmltext;
    }
}

static void Main(string[] args)
{
    string url = "https://www.facebook.com/xuanthulab/";

    var htmltask = GetWebContent(url);
    htmltask.Wait();                                                                // cho hoàn thành tác vụ
    var html = htmltask.Result;                                                     // đọc chuỗi trả về (content)
    Console.WriteLine(html!=null ? html.Substring(0, Math.Min(150, html.Length)): "Lỗi");
}

Chạy thử, nếu truy cập facebook.com sẽ không truy cập được

Tương tự, nếu truy cập google.com sẽ chuyển thành bing.com

Truy cập các trang khác bình thường

Đăng ký theo dõi ủng hộ kênh