- Request GET bất đồng bộ với HttpClient
- ReadAsStreamAsync và ReadAsByteArrayAsync
- Tạo request với SendAsync
- Sử dụng FormUrlEncodedContent
- Sử dụng StringContent
- Sử dụng MultipartFormDataContent
Giới thiệu HttpClient
Lớp HttpClient
được sử dụng để gửi truy vấn HTTP (Http Request Message - Request)
và nhận phản hồi Response (Http Response Message) từ các truy vấn đó.
Lớp này thuộc namespace System.Net.Http
, namespace này chứa các lớp giúp tạo ra sự liên lạc
giữa client và server. Để làm việc với HttpClient dùng những namespace sau:
using System; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; using System.IO; using System.Text;
Phần này thực hiện làm việc với giao thức HTTP nên trước tiên cần hiểu rõ về giao thức này, hãy đọc kỹ phần Giao thức HTTP và địa chỉ Uri, Url ở phần Cấu trúc Uri, Url, Lớp Uri trong C#
Tạo truy vấn GET bất đồng bộ với HttpClient
Để tạo ra truy vấn GET tới một địa chỉ URL, thực hiện phương thức GetAsync(url)
,
đây là phương thức async
khi kết thúc nó trả về đối tượng
HttpResponseMessage
. Từ đối tượng này ta sẽ biết kết quả truy vấn,
và ta có thể đọc được dữ liệu tải về.
// Khởi tạo http client using var httpClient = new HttpClient(); // Thiết lập các Header nếu cần httpClient.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml+json"); // Thực hiện truy vấn GET HttpResponseMessage response = await httpClient.GetAsync(url);
Khi có đối tượng lớp HttpResponseMessage
có thể thực hiện các tác vụ đọc dữ liệu, tham khảo một
số thuộc tính và phương thức:
EnsureSuccessStatusCode() |
Phát sinh Exception nếu truy vấn có mã trả về không thành công (khi thuộc tính IsSuccessStatusCode là false ) |
IsSuccessStatusCode |
Nhận true khi mã trả về thành công, ví dụ mã trạng thái StatusCode nhận giá trị 200 |
StatusCode |
Thuộc tính có kiểu enum HttpStatusCode cho biết mã trạng thái của kết quả
(Như 301 - MovedPermanently, 200 - OK, 404 - NotFound ...),
để chuyển sang số nguyên (int)HttpStatusCode |
ReasonPhrase |
Đoạn text, mô tả thông tin cho mã trạng thái như
OK , MovedPermanently ... |
Headers | HttpResponseHeaders
Thuộc tính kiểu
HttpResponseHeaders chứa tập hợp các header (xem thêm
các header của HTTP Message) của Response.
HttpResponseHeaders kế thừa từ HttpHeaders là tập hợp mà mỗi phần tử
có kiểu KeyValuePair<String,IEnumerable<String>> (biểu diễn
một header httpd - key là tên header và value là tập hợp các chuỗi giá trị của header)
Ví dụ xây dựng phương thực để hiện thị tất cả các header /// In ra thông tin các Header của HTTP Response public static void ShowHeaders(HttpHeaders headers) { Console.WriteLine("CÁC HEADER:"); foreach (var header in headers) { foreach (var value in header.Value) { Console.WriteLine($"{header.Key,25} : {value}"); } } Console.WriteLine(); } Ngoài ra nó còn có một số thuộc tính là các header thông dụng HTTP Respone như Age, Etag, Server ... mà nó đã phân tích các chuỗi header trả về thành các đối tượng tương ứng như TimeSpan, EntityTagHeaderValue, HttpHeaderValueCollection ... xem chi tiết các thuộc tính này tại các header response |
Content |
Thuộc tính kiểu HttpContent , trong đó chứa nội dung (content) và các header liên
quan đến content nếu có (Headers như Content-Type, Content-Length ...), một số phương
thức để lấy content:
|
Ví dụ, tạo truy vấn GET, tải về trang Web - hiện thị các header và trả về content kết quả
/// In ra thông tin các Header của HTTP Response public static void ShowHeaders(HttpHeaders headers) { Console.WriteLine("CÁC HEADER:"); foreach (var header in headers) { foreach (var value in header.Value) { Console.WriteLine($"{header.Key,25} : {value}"); } } Console.WriteLine(); } // Tải về trang web và trả về chuỗi nội dung public static async Task<string> GetWebContent(string url) { // Khởi tạo http client using var httpClient = new HttpClient(); // Thiết lập các Header nếu cần httpClient.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml+json"); try { // Thực hiện truy vấn GET HttpResponseMessage response = await httpClient.GetAsync(url); // Hiện thị thông tin header trả về ShowHeaders(response.Headers); // Phát sinh Exception nếu mã trạng thái trả về là lỗi response.EnsureSuccessStatusCode(); Console.WriteLine($"Tải thành công - statusCode {(int)response.StatusCode} {response.ReasonPhrase}"); Console.WriteLine("Starting read data"); // Đọc nội dung content trả về - ĐỌC CHUỖI NỘI DUNG string htmltext = await response.Content.ReadAsStringAsync(); Console.WriteLine($"Nhận được {htmltext.Length} ký tự"); Console.WriteLine(); return htmltext; } catch (Exception ex) { Console.WriteLine(ex.Message); return null; } }
Khi sử dụng, như trong phương thức Main (chú ý chuyển sang bất đồng bộ)
static async Task Main(string[] args) { var c = await GetWebContent("https://www.google.com/search?q=xuanthulab"); Console.WriteLine(c); }
Mã nguồn tham khảo tại HttpClientExample hoặc tải về tại ex029-httpclient
ReadAsStreamAsync và ReadAsByteArrayAsync đọc nội dung
Ở ví dụ trên, đã dùng ReadAsStringAsync
để đọc content convert thành chuỗi (string).
Ngoài ra, cũng có thể sử dụng ReadAsStreamAsync
để tạo stream để đọc kết quả
và sử dụng ReadAsByteArrayAsync
để đọc hết các byte (mảng các byte) trong content.
Ví dụ sử dụng ReadAsByteArrayAsync
Xây dựng phương thức đọc tài nguyên từ một url và trả về mảng byte là content
var url = "https://raw.githubusercontent.com/xuanthulabnet/jekyll-example/master/images/jekyll-01.png"; byte[] bytes = await DownloadDataBytes(url); string filepath = "anh1.png"; using (var stream = new FileStream (filepath, FileMode.Create, FileAccess.Write, FileShare.None)) { stream.Write (bytes, 0, bytes.Length); Console.WriteLine("save " + filepath); }
Khi sủ dụng, có thể lưu toàn bộ dữ liệu mảng byte ra file. Ví dụ tải một file ảnh về:
static async Task Main(string[] args) { var url = "https://raw.githubusercontent.com/xuanthulabnet/jekyll-example/master/images/jekyll-01.png"; byte[] bytes = await DownloadDataBytes(url); string filepath = "anh1.png"; using (var stream = new FileStream (filepath, FileMode.Create, FileAccess.Write, FileShare.None)) { stream.Write (bytes, 0, bytes.Length); Console.WriteLine("save " + filepath); } }
Ví dụ sử dụng DownloadDataStream
DownloadDataStream trả về một Stream để đọc Content, ví dụ xây dựng phương thức tải một file ảnh từ url cho trước.
// Tải từ url, trả về stream để đọc dữ liệu (xem bài về stream) public static async Task DownloadDataStream (string url, string filename) { var httpClient = new HttpClient(); Console.WriteLine ($"Starting connect {url}"); try { HttpResponseMessage response = await httpClient.GetAsync (url); response.EnsureSuccessStatusCode (); // Lấy Stream để đọc content using var stream = await response.Content.ReadAsStreamAsync(); // THỰC HIỆN ĐỌC Content int SIZEBUFFER = 500; using var streamwrite = File.OpenWrite (filename); // Mở stream để lưu file byte[] buffer = new byte[SIZEBUFFER]; // tạo bộ nhớ đệm lưu dữ liệu khi đọc stream bool endread = false; do // thực hiện đọc các byte từ stream và lưu ra streamwrite { int numberRead = await stream.ReadAsync(buffer, 0, SIZEBUFFER); Console.WriteLine(numberRead); if (numberRead == 0) { endread = true; } else { await streamwrite.WriteAsync(buffer, 0, numberRead); } } while (!endread); Console.WriteLine ("Download success"); } catch (Exception e) { Console.WriteLine (e.Message); throw e; } }
Khi áp dụng
static async Task Main(string[] args) { var url = "https://raw.githubusercontent.com/xuanthulabnet/linux-centos/master/docs/samba1.png"; await DownloadDataStream(url, "anh2.png"); }
Tham khảo mã nguồn HttpClientExampleRead (git) hoặc tải về ex029-2
Tạo request với SendAsync
Ngoài phương thức GetAsync
gửi Request với phương thức GET ở trên ra,
có thể dùng phương thức SendAsync
(hoặc Send
nếu sử dụng code đồng bộ synchronous).
Phương thức này có tham số kiểu HttpRequestMessage
chứa các thông tin về một HTTP Request
sẽ gửi đi (xem thêm HTTP Request),
giúp tùy biến, thêm được nhiều thông tin khi gửi request hơn.
Ví dụ tạo Request:
var httpRequestMessage = new HttpRequestMessage(); httpRequestMessage.Method = HttpMethod.Post; httpRequestMessage.RequestUri = new Uri("https://xuanthulab.net"); /...
Sau khi tạo được HttpRequestMessage có thể thiết lập nhiều thông tin như,
thiết lập method với thuộc tính Method
(giá trị GET
, POST
, DELETE
...), thiết lập địa chỉ truy vấn với thuộc tính RequestUri
,
thiết lập Content của truy vấn với Content
...
Sau đó có thể thực hiện truy vấn để trả về HttpResponseMessage
var response = await httpClient.SendAsync(request);
Sử dụng FormUrlEncodedContent
Để thiết lập Content trong HttpRequestMessage để gửi đến server thì thiết lập thuộc tính
Content bằng các đối tượng thuộc các lớp như: FormUrlEncodedContent
,
StringContent
,
Với FormUrlEncodedContent
bạn có thể tạo Content tương ứng như một Form HTML,
nó chứa các giá trị (key/value) sẽ Post đến Server. Ví dụ sau, nó post đến server hai giá trị
tương ứng key và value là key1/value1 (có thể hiểu tương ứng với phần tử HTML Input có name là key1
và value là value1) và key2/value2 (trường hợp này chứa nhiều giá trị, tương ứng với HTML Multi Select)
static async Task Main(string[] args) { var httpClient = new HttpClient(); var httpRequestMessage = new HttpRequestMessage(); httpRequestMessage.Method = HttpMethod.Post; httpRequestMessage.RequestUri = new Uri("https://postman-echo.com/post"); var parameters = new List<KeyValuePair<string,string>>(); parameters.Add(new KeyValuePair<string,string>("key1","value1")); parameters.Add(new KeyValuePair<string,string>("key2","value2-1")); parameters.Add(new KeyValuePair<string,string>("key2","value2-2")); // Thiết lập Content var content = new FormUrlEncodedContent(parameters); httpRequestMessage.Content = content; // Thực hiện Post var response = await httpClient.SendAsync(httpRequestMessage); var responseContent = await response.Content.ReadAsStringAsync(); Console.WriteLine(responseContent); // Khi chạy kết quả trả về cho biết Server đã nhận được dữ liệu Post đến }
Sử dụng StringContent
Có thể gán Content bằng đối tượng kiểu StringContent chứa chuỗi nội dung (sử dụng cách này để tạo truy vấn Webservice API với Content là JSON)
static async Task Main(string[] args) { var httpClient = new HttpClient(); var httpRequestMessage = new HttpRequestMessage(); httpRequestMessage.Method = HttpMethod.Post; httpRequestMessage.RequestUri = new Uri("https://postman-echo.com/post"); // Tạo StringContent string jsoncontent = "{\"value1\": \"giatri1\", \"value2\": \"giatri2\"}"; var httpContent = new StringContent(jsoncontent, Encoding.UTF8, "application/json"); httpRequestMessage.Content = httpContent; var response = await httpClient.SendAsync(httpRequestMessage); var responseContent = await response.Content.ReadAsStringAsync(); Console.WriteLine(responseContent); }
Sử dụng MultipartFormDataContent
Bạn có thể gán Content bằng đối tượng kiểu MultipartFormDataContent, để post dữ liệu nhiều thành phần (multipart/form-data), vừa có dữ liệu như các phần tử của HTML Form vừa có thể kèm file.
Ví dụ, tạo ra truy vấn tương tự form HTML post các dữ liệu: có file đính kèm, có hai phần tử
var httpClient = new HttpClient(); var httpRequestMessage = new HttpRequestMessage(); httpRequestMessage.Method = HttpMethod.Post; httpRequestMessage.RequestUri = new Uri("https://postman-echo.com/post"); // Tạo đối tượng MultipartFormDataContent var content = new MultipartFormDataContent(); // Tạo StreamContent chứa nội dung file upload, sau đó đưa vào content Stream fileStream = System.IO.File.OpenRead("Program.cs"); content.Add(new StreamContent(fileStream), "fileupload", "abc.xyz"); // Thêm vào MultipartFormDataContent một StringContent content.Add(new StringContent("value1"), "key1"); // Thêm phần tử chứa mạng giá trị (HTML Multi Select) content.Add(new StringContent("value2-1"), "key2[]"); content.Add(new StringContent("value2-2"), "key2[]"); httpRequestMessage.Content = content; var response = await httpClient.SendAsync(httpRequestMessage); var responseContent = await response.Content.ReadAsStringAsync(); Console.WriteLine(responseContent);
Tham khảo mã nguồn HttpClientExampleSendAsync (git) hoặc tải về ex031