Kiến thức cần biết:
- Biết lập trình C#
- Biết lập trình ASP.NET Core
- Biết cơ bản về RESTful API
- Cài đặt môi trường phát triển .NET 6 hoặc các phiên bản sau của Microsoft
- Làm việc với CSDL MongoDB
Tạo dự án với .NET CLI
- Chạy lệnh sau để tạo dự án:
dotnet new webapi -o MyStoreApi
- Chuyển lệnh đến thư mục MyStoreApi và thêm trình điều khiển Cơ sở dữ liệu MongoDB vào dự án với lệnh sau:
cd ./MyStoreApi dotnet add package MongoDB.Driver
Thêm mô hình thực thể
- Tạo thư mục "Models" trong thư mục gốc của dự án
- Thêm lớp "Product" vào trong thư mục Models và thực hiện mã lệnh sau:
using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; namespace MyStoreApi.Models; public class Product { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string? Id { set; get; } [BsonElement("Name")] public string ProductName { get; set; } = null!; public decimal Price { get; set; } public string Category { get; set; } = null!; public string Description { get; set; } = null!; }
Trong định nghĩa lớp trên thuộc tính
Id
có nghĩa:- Thuộc tính
Id
cần thiết để ánh xạ đối tượng Common Language Runtime (CLR) vào CSDL MongoDB. - Chú thích
[BsonId]
để đặt thuộc tính này thành khóa chính của tài liệu. - Chú thích bằng
[BsonRepresentation (BsonType.ObjectId)]
để cho phép truyền tham số dưới dạng chuỗi kiểu thay vì cấu trúc ObjectId. Mongo xử lý việc chuyển đổi từ chuỗi thànhObjectId
.
- Thuộc tính
Thêm cấu hình mô hình với CSDL MongoDB
- Thêm cấu hình CSDL trong tệp
appsetting.json
:{ "MyStoreDatabase": { "ConnectionString": "mongodb://localhost:27017", "DatabaseName": "MyStore", "ProductsCollectionName": "Products" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" }
- Thêm lớp
MyStoreDbSettings
vào thư mụcModels
và thực hiện mã lệnh sau:namespace MyStoreApi.Models; public class MyStoreDbSettings { public string ConnectionString { get; set; } = null!; public string DatabaseName { get; set; } = null!; public string ProductsCollectionName { get; set; } = null!; }
Lớp
MyStoreDbSettings
được sử dụng để lưu trữ các giá trị thuộc tínhMyStoreDatabase
của tệpappsettings.json
. Tên thuộc tính JSON và C# được đặt tên giống nhau để dễ dàng quá trình ánh xạ. - Thêm mã lệnh sau vào tệp Program.cs:
using MyStoreApi.Models; using MyStoreApi.Services; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<MyStoreDbSettings>( builder.Configuration.GetSection("MyStoreDatabase"));
Trong mã lệnh trên, phiên bản cấu hình mà phần
MyStoreDatabase
của tệpappsettings.json
liên kết được đăng ký trong vùng chứa "chèn phụ thuộc" (Dependency Injection - DI). Ví dụ: thuộc tínhConnectionString
của đối tượngMyStoreDbSettings
được điền với thuộc tínhMyStoreDatabase: ConnectionString
trongappsettings.json
.
Thêm các thao tác CRUD
- Thêm thư mục Services vào trong thư mục gốc của dự án
- Thêm lớp ProductService vào thư mục Services và thực hiện mã lệnh sau:
using MyStoreApi.Models; using MyStoreApi.Services; using Microsoft.Extensions.Options; using MongoDB.Driver; using MongoDB.Bson; namespace MyStoreApi.Services; public class ProductsService { private readonly IMongoCollection<Product> _productsCollection; public ProductsService( IOptions<MyStoreDbSettings> myStoreDbSettings) { var mongoClient = new MongoClient( myStoreDbSettings.Value.ConnectionString); var mongoDatabase = mongoClient.GetDatabase( myStoreDbSettings.Value.DatabaseName); _productsCollection = mongoDatabase.GetCollection<Product>( myStoreDbSettings.Value.ProductsCollectionName); } public async Task<List<Product>> GetAsync() => await _productsCollection.Find(_ => true).ToListAsync(); public async Task<Product?> GetAsync(string id) => await _productsCollection.Find(x => x.Id == id).FirstOrDefaultAsync(); public async Task CreateAsync(Product newProduct) => await _productsCollection.InsertOneAsync(newProduct); public async Task UpdateAsync(string id, Product updatedProduct) => await _productsCollection.ReplaceOneAsync(x => x.Id == id, updatedProduct); public async Task RemoveAsync(string id) => await _productsCollection.DeleteOneAsync(x => x.Id == id); }
Trong đoạn mã lệnh trên, một đối tượng
MyStoreDbSettings
được truy xuất từ "chèn phụ thuộc" (Dependency Injection - DI) thông qua phương thức chèn hàm khởi tạo. Kỹ thuật này cung cấp quyền truy cập vào các giá trị cấu hìnhappsettings.json
đã được thêm vào phần Thêm mô hình cấu hình với CSDL MongoDB. - Thêm mã lệnh sau vào tệp Program.cs
using MyStoreApi.Models; using MyStoreApi.Services; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.Configure<MyStoreDbSettings>( builder.Configuration.GetSection("MyStoreDatabase")); builder.Services.AddSingleton<ProductsService>()
Thêm Controller
Thêm lớp ProductsController
vào thư mục Controllers
và thực hiện mã lệnh sau:
using MyStoreApi.Models;
using MyStoreApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace MyStoreApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly ProductsService _productsService;
public ProductsController(ProductsService productsService) =>
_productsService = productsService;
[HttpGet]
public async Task<List<Product>> Get() =>
await _productsService.GetAsync();
[HttpGet("{id:length(24)}")]
public async Task<ActionResult<Product>> Get(string id)
{
var product = await _productsService.GetAsync(id);
if (product is null)
{
return NotFound();
}
return product;
}
[HttpPost]
public async Task<IActionResult> Post(Product newProduct)
{
await _productsService.CreateAsync(newProduct);
return CreatedAtAction(nameof(Get), new { id = newProduct.Id }, newProduct);
}
[HttpPut("{id:length(24)}")]
public async Task<IActionResult> Update(string id, Product updatedProduct)
{
var product = await _productsService.GetAsync(id);
if (product is null)
{
return NotFound();
}
updatedProduct.Id = product.Id;
await _productsService.UpdateAsync(id, updatedProduct);
return NoContent();
}
[HttpDelete("{id:length(24)}")]
public async Task<IActionResult> Delete(string id)
{
var product = await _productsService.GetAsync(id);
if (product is null)
{
return NotFound();
}
await _productsService.RemoveAsync(product.Id ?? "");
return NoContent();
}
}
Trong Controller của Web API trên:
- Sử dụng lớp
ProductsService
để thực hiện các thao tácCRUD
. - Chứa các phương thức hành động để hỗ trợ các yêu cầu
HTTP GET
,POST
,PUT
vàDELETE
. - Gọi phương thức
CreatedAtAction()
trong phương thứcpublic async Task<IActionResult> Post(Product newProduct)
để trả về phản hồi (response
)HTTP 201
. Mã trạng thái201
là phản hồi tiêu chuẩn cho phương thứcHTTP POST
tạo tài nguyên mới trên máy chủ.CreatedAtAction()
cũng thêm tiêu đề Vị trí (Location
) vào phản hồi (response
). Tiêu đề Vị trí (Location
) chỉ định URI của sản phẩm mới được tạo.
Kiểm thử Web API
Để kiểm thử Web API thực hiện các bước như sau:
- Chạy Web API với lệnh sau:
$ dotnet run ... Building... info: Microsoft.Hosting.Lifetime[14] Now listening on: https://localhost:7171 ...
Lưu ý: khi thực chạy lệnh trên cho chúng ta biết Web API được biên dịch và chạy tại đường dẫn https://localhost:7171 (trên cổng 7171).
- Kiểm thử Web API với Swagger: vào trình duyệt với đường dẫn sau https://localhost:7171/swagger