

Kiến trúc .NET Core và Triển khai Kestrel Web Server
- 04-04-2025
- Toanngo92
- 0 Comments
Mục lục
Kiến trúc .NET Core
Giới thiệu về .NET Core
- .NET Core là một nền tảng phát triển mã nguồn mở, được tạo ra và duy trì bởi cộng đồng .NET.
- Mục tiêu của .NET Core là tích hợp nhiều nền tảng khác nhau, giúp xây dựng ứng dụng đa nền tảng.
- Bất kể hệ điều hành nào (Windows, Linux, macOS), .NET Core có thể được sử dụng để phát triển ứng dụng.
Cấu trúc .NET Core trong hệ thống NET Stack
- Kiến trúc .NET Core được minh họa trong Hình 8.1.
- Hệ thống NET Stack gồm các thành phần:
- .NET Framework
- .NET Core
- BCL (Base Class Library) / Runtime / Compilers / NuGet Packages

Thư viện Runtime và NuGet Packages
- Trước đây, các thư viện runtime, trình biên dịch và gói NuGet được dùng bởi .NET Framework và các thư viện .NET khác.
- Hiện nay, ngoài các gói chung, còn có các thư viện đặc thù cho từng nền tảng.
- Các kiểu dữ liệu (data types) được lưu trữ trong Common Type System, đảm bảo tính tương thích giữa các nền tảng.
- .NET Core là một nền tảng mở, cho phép các framework như ASP.NET Core và Universal Windows Platform (UWP) mở rộng chức năng của hệ thống.
Các tính năng của .NET Core
Tính năng | Mô tả |
---|---|
Cross-Platform (Đa nền tảng) | .NET Core mở rộng triết lý “Build once, run anywhere”, có thể chạy trên mọi hệ điều hành như Windows, Linux, macOS. |
Command Line Interface (CLI) | .NET Core cung cấp nhiều công cụ CLI hỗ trợ phát triển, giúp lập trình viên làm việc trên terminal hiệu quả hơn. |
Focus on Logic (Tập trung vào logic) | Hỗ trợ Tích hợp liên tục (CI) và Triển khai liên tục (CD), giúp tăng cường quy trình DevOps. |
Languages and IDEs (Ngôn ngữ và Môi trường phát triển) | Hỗ trợ nhiều ngôn ngữ lập trình như C#, VB.NET, F# và các IDE phổ biến như Visual Studio, VS Code, Sublime. |
Compatibility and Support (Tương thích và Hỗ trợ) | Tương thích với .NET Framework, .NET Standard, Mono API, Xamarin. Cả Microsoft và cộng đồng đều cung cấp hỗ trợ rộng rãi. |
Device Focus (Tập trung vào thiết bị) | Hỗ trợ phát triển ứng dụng cho nhiều lĩnh vực như di động (mobile), IoT (Internet of Things), trò chơi (gaming). |
RESTful APIs (Hỗ trợ REST API) | Không hỗ trợ WCF, thay vào đó khuyến khích sử dụng REST API để giao tiếp giữa các hệ thống. |
Một số khía cạnh quan trọng trong kiến trúc .NET Core bao gồm:
- Phương thức
Main()
trong ứng dụng Core. - Máy chủ Kestrel.
- Kiến trúc Open Web Interface (OWIN).
- REST API.
Điểm vào chương trình ASP.NET MVC
- Khi tạo một ứng dụng ASP.NET Core Web, hệ thống sẽ tự động tạo một tệp Program.cs.
- Tệp này chứa phương thức
Main()
, được định nghĩa như sau:
public static void Main()
Với các phiên bản .NET core, chúng ta sẽ không nhìn thấy phương thức main này nữa, nhưng bản chất vẫn tồn tại dưới dạng ẩn.

Program.cs
trong một ứng dụng ASP.NET Core.Giải thích nội dung tệp Program.cs
này:
- Khởi tạo ứng dụng bằng
WebApplication.CreateBuilder(args)
. - Thêm dịch vụ vào container:
builder.Services.AddControllersWithViews()
để hỗ trợ MVC. - Xây dựng ứng dụng với
builder.Build()
. - Cấu hình pipeline xử lý HTTP requests:
- Xử lý lỗi bằng
UseExceptionHandler("/Home/Error")
nếu ứng dụng không chạy trong môi trường phát triển. - Bật HSTS để tăng cường bảo mật HTTP.
- Bật redirect HTTPS với
UseHttpsRedirection()
. - Hỗ trợ tệp tĩnh (
UseStaticFiles()
). - Bật định tuyến (
Routing
) và ủy quyền (Authorization
).
- Xử lý lỗi bằng
- Thiết lập tuyến đường mặc định (
Default Route
):{controller=Home}/{action=Index}/{id?}
=> Mặc địnhHomeController
và phương thứcIndex()
.
- Chạy ứng dụng bằng
app.Run();
.
Tệp này quan trọng như thế nào?
- Trong ASP.NET Core 6 trở lên,
Program.cs
là điểm vào chính của ứng dụng. - Nó thay thế
Startup.cs
, giúp đơn giản hóa khởi tạo và cấu hình ứng dụng.
Phương thức Main gọi đến phương thức CreateHostBuilder()
, phương thức CreateHostBuilder()
trả về một đối tượng thực thi giao diện IHostBuilder
. trên đối tượng IHostBuilder
, phương thức Build()
được gọi để xây dựng một web host. Sau đó, nếu đây là ứng dụng web ASP.NET Core, Run()
sẽ được gọi để khởi động web host. Khi web host chạy, phương thức Run()
được gọi để chạy ứng dụng web và bắt đầu xử lý các yêu cầu HTTP đến.
Máy chủ Kestrel
Kestrel là một máy chủ web đa nền tảng dành cho ASP.NET Core, có thể hoạt động trên tất cả các nền tảng .NET. Trong ASP.NET Core, nó đóng vai trò là máy chủ nội bộ. Nó được tích hợp mặc định trong ứng dụng .NET Core. Điều này chỉ ra rằng máy chủ này tương thích với tất cả các nền tảng và phiên bản .NET Core.
Tệp dotnet.exe là tiến trình dùng để host ứng dụng trong Kestrel. Với cách tiếp cận host trong tiến trình, Kestrel hoạt động như là máy chủ web. Nó cũng có thể được dùng theo những cách khác cho các kiểu host ngoài tiến trình:
- Kestrel có thể được sử dụng như một máy chủ web để nhận các yêu cầu HTTP từ Internet.
- Kestrel cũng có thể được sử dụng kết hợp với một máy chủ proxy ngược.

Hình 8.4 cho thấy luồng dữ liệu đi vào và đi ra trong máy chủ Kestrel.
Khi ứng dụng ASP.NET Core được chạy bằng .NET Core CLI, máy chủ web Kestrel sẽ được kích hoạt. Nó chịu trách nhiệm xử lý và xử lý các yêu cầu HTTP đến.
Mặc định, bất kỳ dự án ứng dụng web ASP.NET Core nào cũng có một phương thức tên là CreateHostBuilder
. Phương thức này gọi ConfigureWebHostDefaults
, trong đó sử dụng hàm UseKestrel
bên trong. Điều này được thể hiện trong Hình 8.5.

Hơn nữa, máy chủ Kestrel tận dụng nhiều cấu hình khác nhau được cung cấp bởi các biến môi trường (environment variables), tệp appsettings.json
, và thậm chí là môi trường lập trình (coding medium).
Khi một ứng dụng web đang chạy, nó sẽ tập trung vào các URL đã được di chuyển (moved). Kestrel mặc định theo dõi hai URL nếu không có cấu hình nào được cung cấp.
Các URL này như sau:
- http://localhost:5000
- https://localhost:5001 (nếu có sẵn chứng chỉ phát triển cục bộ)
Kiến trúc OWIN
OWIN cho .NET là một framework mã nguồn mở cung cấp các yêu cầu giao diện để cho phép máy chủ web và ứng dụng giao tiếp với nhau.
Các chương trình web có thể được tách biệt khỏi máy chủ web bằng cách sử dụng OWIN. Nó thiết lập một cơ chế chung cho middleware để xử lý yêu cầu và phản hồi theo một đường ống. Các ứng dụng, máy chủ và middleware dựa trên OWIN có thể giao tiếp với các thành phần lõi và middleware của ASP.NET.
Hỗ trợ cho OWIN có thể được tìm thấy trong Trình quản lý gói NuGet. Hình 8.6 minh họa trình quản lý này.

ASP.NET phụ thuộc rất nhiều vào IIS cho việc triển khai. Sự phụ thuộc này giới hạn khả năng di động của các ứng dụng ASP.NET. Do đó, OWIN được tạo ra để làm cho ASP.NET trở nên mô-đun hơn bằng cách giảm sự phụ thuộc và tạo ra một framework rời rạc (loose coupling).
Web API RESTful
REST (Representational State Transfer) là một cách tiếp cận kiến trúc để thiết lập các dịch vụ API Web RESTful cho phép các ứng dụng web giao tiếp dễ dàng hơn. Các thành phần được xem như là tài nguyên, và các tài nguyên này có thể được truy cập thông qua một giao diện chung sử dụng các phương thức chuẩn của giao thức HTTP.
Mặc dù REST không hoàn toàn liên quan đến HTTP, nhưng nó thường được kết hợp với HTTP. Dựa trên kiến trúc REST, RESTful API là một dịch vụ nhẹ, dễ bảo trì và có thể mở rộng. Nó cung cấp quyền truy cập từ một ứng dụng đến một máy khách gọi trong một cách bảo mật, chuẩn hóa và không lưu trạng thái (stateless).
Bảng 8.1: Các thuộc tính HTTP cốt lõi trong hệ thống REST
Lệnh | Mục đích |
---|---|
GET | Truy cập tài nguyên ở chế độ chỉ đọc |
POST | Tạo mới một tài nguyên |
DELETE | Xóa một tài nguyên |
PUT | Cập nhật tài nguyên hiện có hoặc tạo mới một tài nguyên |
Hình 8.7 mô tả cách RESTful API giao tiếp với một ứng dụng và các tài nguyên.

RESTful API là cách hiệu quả nhất để truy cập các tài nguyên nằm ở các môi trường khác nhau. Ví dụ, một máy khách có thể cần quyền để truy cập tài liệu, video, hoặc hình ảnh được lưu trữ trên máy chủ. Các dịch vụ RESTful sẽ thiết lập hoặc định nghĩa cách mà các tài nguyên này có thể được truy cập.
Microsoft Visual Studio 2022 cũng hỗ trợ tạo ứng dụng dựa trên RESTful API. Hình 8.8 minh họa một mẫu RESTful API trong Visual Studio 2022.

Ví dụ:
[HttpGet]
public IEnumerable<WeatherForecast> Get() {
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
Khi một phương thức Get
được sử dụng để lấy dữ liệu từ dịch vụ này, sau một vài xử lý cơ bản, dữ liệu kết quả sẽ xuất hiện dưới dạng mảng JSON. Hình 8.9 minh họa kết quả này.

Ví dụ 2:
[HttpGet("{id}")]
public IEnumerable<WeatherForecast> Get(int id) {
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
Phần sửa đổi này cho phép cung cấp tham số (argument) từ trình duyệt như được hiển thị trong Hình 8.10 khi gọi dịch vụ.

Sự khác biệt giữa GraphQL API và REST API
GraphQL là một ngôn ngữ truy vấn mạnh mẽ dành cho API và là môi trường thực thi các truy vấn đó với dữ liệu hiện có. Được phát triển bởi Facebook vào năm 2012 và sau đó mã nguồn mở vào năm 2015, GraphQL đã được cộng đồng phát triển web chấp nhận rộng rãi nhờ tính linh hoạt, hiệu quả và khả năng giải quyết những thách thức thường gặp trong REST API truyền thống.
Khám phá GraphQL
Các khái niệm chính của GraphQL bao gồm:
Truy vấn dữ liệu khai báo (Declarative Data Retrieval)
GraphQL cho phép khách hàng (client) yêu cầu chính xác dữ liệu mà họ cần. Trái ngược với REST – nơi máy chủ định nghĩa cấu trúc phản hồi – trong GraphQL, client sẽ chỉ rõ dữ liệu họ cần trong một truy vấn, từ đó chỉ nhận đúng những gì cần thiết.
Endpoint duy nhất (Unified Endpoint)
Khác với REST thường có nhiều endpoint cho các tài nguyên khác nhau, GraphQL thường chỉ sử dụng một endpoint duy nhất. Điều này giúp giảm thiểu số lượng request và giảm độ phức tạp trong giao tiếp client-server.
Lược đồ có kiểu mạnh (Strongly Typed Schema)
API GraphQL được xác định bởi một lược đồ (schema) định nghĩa rõ ràng các kiểu dữ liệu và mối quan hệ giữa chúng. Điều này mang lại cấu trúc nhất quán và rõ ràng cho giao tiếp giữa client và server, đồng thời giúp xác thực dữ liệu tốt hơn.
Tích hợp dữ liệu thời gian thực qua subscription (Real-time Data Integration via Subscriptions)
GraphQL hỗ trợ cập nhật dữ liệu thời gian thực thông qua cơ chế subscription. Client có thể đăng ký nhận các sự kiện, và server sẽ tự động gửi thông báo đến các client đăng ký khi dữ liệu có thay đổi.
Cấu trúc truy vấn dạng phân cấp (Hierarchical Query Structure)
Truy vấn GraphQL sử dụng cách tổ chức dạng phân cấp, phản ánh cấu trúc của dữ liệu phản hồi. Cách tổ chức phân cấp này giúp đơn giản hóa việc hiểu truy vấn, sửa đổi và mở rộng cho lập trình viên.
Các thành phần của GraphQL
Các thành phần của GraphQL được liệt kê trong Bảng 8.2 dưới đây:
Bảng 8.2: Các thành phần của GraphQL
Thành phần (Component Name) | Mô tả (Description) |
---|---|
Queries | Client sử dụng truy vấn để yêu cầu dữ liệu cụ thể từ máy chủ. |
Mutations | Dùng để thay đổi dữ liệu trên máy chủ. |
Subscriptions | Cho phép cập nhật dữ liệu thời gian thực bằng cách để client đăng ký lắng nghe các sự kiện cụ thể. |
Types and Fields | Lược đồ GraphQL định nghĩa các kiểu dữ liệu và trường dữ liệu, thể hiện cấu trúc của dữ liệu. |
Resolvers | Quy định cách một trường (field) trong lược đồ được tính toán. Resolvers mô tả cách lấy hoặc thao tác dữ liệu bằng logic cụ thể. |
8.6.3 So sánh đặc điểm giữa GraphQL API và REST API
Bảng 8.3 dưới đây chỉ ra sự khác biệt giữa GraphQL và REST APIs:
Bảng 8.3: Sự khác nhau giữa GraphQL và REST API
Tính năng (Feature) | GraphQL | REST API |
---|---|---|
Lấy dữ liệu (Data Fetching) | Cho phép truy vấn dữ liệu cụ thể trong một yêu cầu duy nhất, giảm thiểu việc truy vấn lặp hoặc thiếu dữ liệu. | Thường yêu cầu nhiều endpoint để lấy dữ liệu khác nhau, dễ dẫn đến thiếu hoặc thừa dữ liệu. |
Endpoint | Thường chỉ dùng một endpoint (ví dụ /graphql ). | Gồm nhiều endpoint khác nhau, mỗi endpoint tương ứng với một tài nguyên cụ thể. |
Định dạng phản hồi (Response Format) | Máy khách chỉ nhận dữ liệu đã yêu cầu, giúp giảm dung lượng phản hồi. | Máy chủ trả về toàn bộ dữ liệu của tài nguyên, có thể gây dư thừa dữ liệu không cần thiết. |
Tính linh hoạt (Flexibility) | Client xác định cấu trúc dữ liệu mong muốn trong truy vấn. | Server xác định cấu trúc dữ liệu trả về, client không kiểm soát được. |
Phiên bản (Versioning) | Không cần versioning vì client có thể tự định nghĩa truy vấn phù hợp với yêu cầu. | Thường cần tạo phiên bản (v1, v2…) để tránh lỗi tương thích khi API thay đổi. |