C# cơ bản .NET Core

Phần này tìm hiểu tạo ra một máy chủ HTTP đơn giản với lớp HttpListener. Thông thường để có đầy đủ các tính năng khi triển khai ứng dụng chúng ta có thể sử dụng dịch vụ HTTP hoàn chỉnh như IIS, Apache HTTPD, Nginx hay Kestrel. Tuy vậy, để nhanh chóng có thể tạo dịch vụ lắng nghe các yêu cầu HTTP gửi đến (Http Request Message) và trả về Response (Http Message Response) thích hợp thì có thể dùng đến HttpListener

Lớp HttpListener

Lớp HttpListener giúp tạo ra dịch vụ với giao thức HTTP, nó lắng nghe các yêu cầu HTTP Request gửi đến và trả về HTTP Respone. Dịch vụ HTTP hoạt động và tồn tại cùng với sự tồn tại của đối tượng HttpListener.

Một số phương thức thuộc tính của lớp HttpListener

Thành viên Diễn tả
IsSupported Phương thức tĩnh kiểu bool, cho biết máy có hỗ trợ HttpListener hay không
Prefixes Thuộc tính, nó chứa các chuỗi cấu trúc URI mà HttpListener làm việc. Ví dụ để nó làm việc trên cổng 8080, giao thức http:// thì chuỗi đó là http://*:8080/ và làm việc trên cổng 443 thì chuỗi là https://*/
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://*:8080/");
listener.Prefixes.Add("https://*/");
Start() Bắt đầu cho phép nhận các yêu cầu (HTTP Request) gửi đến.
Stop() Dừng dịch vụ
GetContextAsync() Chờ kết tạo một kết nối client gửi đến và thực hiện bất đồng bộ nhận thông tin gửi đến bởi client nếu có. Trả về Task với thuộc tính Result khi kết thúc là đối tượng kiểu HttpListenerContext chứa thông tin gửi đến (request) và thông tin sẽ trả về response, khi đối tượng này huỷ thì respone sẽ trả về cho clien truy cập.
HttpListenerContext   context  = await listener.GetContextAsync();
HttpListenerRequest   request  = context.Request; // chứa thông tin gửi đến
HttpListenerResponse  response = context.Response;// các nội dung trả về thiết lập vào respone

Code tạo máy chủ Http cơ bản như sau:

// Mảng chứa địa chỉ Http lắng nghe
// http =  giao thức http, * = ip bất kỳ, 8080 = cổng lắng nghe
string[] prefixes  = new string[] { "http://*:8080/" };

HttpListener listener = new HttpListener();

if (!HttpListener.IsSupported) throw new Exception ("Hệ thống hỗ trợ HttpListener.");

if (prefixes == null || prefixes.Length == 0) throw new ArgumentException ("prefixes");

foreach (string s in prefixes) {
    listener.Prefixes.Add (s);
}

Console.WriteLine ("Server start ...");

// Http bắt đầu lắng nghe truy vấn gửi đến
listener.Start();

// Vòng lặp chấp nhận và xử lý các client kết nối
do
{
    // Chấp nhận khi có cliet kết nối đế
    HttpListenerContext context = await listener.GetContextAsync();

    // ....
    // Xử lý context - đọc  thông tin request,  ghi thông tin response
    // ... ví dụ như sau:

    var response = context.Response;                                        // lấy HttpListenerResponse
    var outputstream = response.OutputStream;                               // lấy Stream lưu nội dung gửi cho client

    context.Response.Headers.Add("content-type", "text/html");              // thiết lập respone header
    byte[] buffer = System.Text.Encoding.UTF8.GetBytes("Hello world!");     // dữ liệu content
    response.ContentLength64 = buffer.Length;
    await outputstream.WriteAsync(buffer,0,buffer.Length);                  // viết content ra stream
    outputstream.Close();                                                   // Đóng stream (gửi về cho cliet)

}
while (listener.IsListening);

Ví dụ tạo máy chủ HTTP đơn giản bằng HttpListener

Source Code

// Chạy một HTTP Server, prefixes example: new string[] { "http://*:8080/" }
class MyHttpServer
{
private HttpListener listener;
public MyHttpServer(params string[] prefixes)
{
if (!HttpListener.IsSupported)
throw new Exception ("Máy không hỗ trợ HttpListener.");
if (prefixes == null || prefixes.Length == 0)
throw new ArgumentException ("prefixes");
// Khởi tạo HttpListener
listener = new HttpListener ();
foreach (string prefix in prefixes)
listener.Prefixes.Add(prefix);
}
public async Task StartAsync()
{
// Bắt đầu lắng nghe kết nối HTTP
listener.Start();
do
{
try
{
Console.WriteLine($"{DateTime.Now.ToLongTimeString()} : waiting a client connect");
// Một client kết nối đến
HttpListenerContext context = await listener.GetContextAsync();
await ProcessRequest(context);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine("...");
}
while (listener.IsListening);
}
// Xử lý trả về nội dung tùy thuộc vào URL truy cập
// / hiện thị dòng Hello World
// /stop dừng máy chủ
// /json trả về một nội dung json
// /anh2.png trả về một file ảnh
// /requestinfo thông tin truy vấn
async Task ProcessRequest(HttpListenerContext context)
{
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
Console.WriteLine($"{request.HttpMethod} {request.RawUrl} {request.Url.AbsolutePath}");
// Lấy stream / gửi dữ liệu về cho client
var outputstream = response.OutputStream;
switch (request.Url.AbsolutePath)
{
case "/requestinfo":
{
// Gửi thông tin về cho Client
context.Response.Headers.Add("content-type", "text/html");
context.Response.StatusCode = (int) HttpStatusCode.OK;
string responseString = this.GenerateHTML(request);
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
await outputstream.WriteAsync(buffer,0,buffer.Length);
}
break;
case "/":
{
byte[] buffer = System.Text.Encoding.UTF8.GetBytes("Hello world!");
response.ContentLength64 = buffer.Length;
await outputstream.WriteAsync(buffer,0,buffer.Length);
}
break;
case "/stop":
{
listener.Stop();
Console.WriteLine("stop http");
}
break;
case "/json":
{
response.Headers.Add("Content-Type", "application/json");
var product = new {
Name = "Macbook Pro",
Price = 2000,
Manufacturer = "Apple"
};
string jsonstring = JsonConvert.SerializeObject(product);
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(jsonstring);
response.ContentLength64 = buffer.Length;
await outputstream.WriteAsync(buffer,0,buffer.Length);
}
break;
case "/anh2.png":
{
response.Headers.Add("Content-Type", "image/png");
byte[] buffer = await File.ReadAllBytesAsync("anh2.png");
response.ContentLength64 = buffer.Length;
await outputstream.WriteAsync(buffer,0,buffer.Length);
}
break;
default:
{
response.StatusCode = (int)HttpStatusCode.NotFound;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes("NOT FOUND!");
response.ContentLength64 = buffer.Length;
await outputstream.WriteAsync(buffer,0,buffer.Length);
}
break;
}
// switch (request.Url.AbsolutePath)
// Đóng stream để hoàn thành gửi về client
outputstream.Close();
}
// Tạo nội dung HTML trả về cho Client (HTML chứa thông tin về Request)
public string GenerateHTML (HttpListenerRequest request) {
string format = @"<!DOCTYPE html>
<html lang=""en"">
<head>
<meta charset=""UTF-8"">
{0}
</head>
<body>
{1}
</body>
</html>";
string head = "<title>Test WebServer</title>";
var body = new StringBuilder ();
body.Append ("<h1>Request Info</h1>");
body.Append ("<h2>Request Header:</h2>");
// Header infomation
var headers = from key in request.Headers.AllKeys
select $"<div>{key} : {string.Join(",", request.Headers.GetValues(key))}</div>";
body.Append (string.Join ("", headers));
//Extract request properties
body.Append ("<h2>Request properties:</h2>");
var properties = request.GetType ().GetProperties ();
foreach (var property in properties) {
var name_pro = property.Name;
string value_pro;
try {
value_pro = property.GetValue (request).ToString ();
} catch (Exception e) {
value_pro = e.Message;
}
body.Append ($"<div>{name_pro} : {value_pro}</div>");
};
string html = string.Format (format, head, body.ToString ());
return html;
}
}
view raw httplistener.cs hosted with ❤ by GitHub

Sử dụng

static async Task Main(string[] args)
{
    var server = new MyHttpServer(new string[] {"http://*:8080/"});
    await server.StartAsync();
}

Truy cập thử với http://localhost:8080/requestinfo

Tham khảo mã nguồn WebListener (git) hoặc tải về ex035


Đăng ký nhận bài viết mới