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
Idcó nghĩa:- Thuộc tính
Idcầ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
MyStoreDbSettingsvào thư mụcModelsvà 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ínhMyStoreDatabasecủ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
MyStoreDatabasecủa tệpappsettings.jsonliên kết được đăng ký trong vùng chứa "chèn phụ thuộc" (Dependency Injection - DI). Ví dụ: thuộc tínhConnectionStringcủa đối tượngMyStoreDbSettingsđược điền với thuộc tínhMyStoreDatabase: ConnectionStringtrongappsettings.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,PUTvà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ái201là phản hồi tiêu chuẩn cho phương thứcHTTP POSTtạ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
