Từ thiết lập dự án ban đầu bằng .NET CLI cho đến định cấu hình phần mềm trung gian, bộ điều khiển và dịch vụ, hãy tìm hiểu từng bước để xây dựng một API mạnh mẽ. Khám phá các phương pháp hay nhất để chèn phần phụ thuộc, hành động không đồng bộ và xử lý các trường hợp ngoại lệ để tạo các ứng dụng web hiệu quả, có thể mở rộng.
Sử dụng .NET CLI để tạo dự án API Web mới. Điều này thiết lập cấu trúc dự án cơ bản bao gồm Program.cs để khởi động và bộ điều khiển WeatherForecast làm ví dụ.
dotnet new webapi -n MyWebApi
.NET 8 tiếp tục xu hướng hướng tới các API tối thiểu, cho phép bạn định cấu hình các dịch vụ và điểm cuối một cách đơn giản và ngắn gọn trực tiếp trong tệp Program.cs.
var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapGet("/", () => "Hello, World!"); app.Run();
Bộ điều khiển xử lý các yêu cầu HTTP đến và phản hồi lại máy khách. Chúng được xác định bằng cách kế thừa từ ControllerBase và chú thích bằng [ApiController].
[ApiController] [Route("[controller]")] public class MyController : ControllerBase { [HttpGet] public IActionResult Get() => Ok("Hello from MyController"); }
Tính năng tiêm phụ thuộc (DI) tích hợp của .NET Core giúp dễ dàng quản lý các phần phụ thuộc. Bạn có thể đưa các dịch vụ vào bộ điều khiển của mình thông qua hàm tạo của chúng.
public class MyService { public string GetMessage() => "Injected message"; } public class MyController : ControllerBase { private readonly MyService _myService; public MyController(MyService myService) { _myService = myService; } [HttpGet] public IActionResult Get() => Ok(_myService.GetMessage()); }
Các dịch vụ (như ngữ cảnh cơ sở dữ liệu, dịch vụ tùy chỉnh, v.v.) được định cấu hình trong tệp Program.cs, giúp chúng sẵn sàng để chèn phần phụ thuộc trong toàn bộ ứng dụng của bạn.
builder.Services.AddScoped<MyService>();
.NET hỗ trợ các tệp cấu hình dành riêng cho môi trường (appsettings.json, appsinstall.Development.json, v.v.), cho phép thực hiện các cài đặt khác nhau dựa trên môi trường của ứng dụng.
// appsettings.Development.json { "Logging": { "LogLevel": { "Default": "Debug" } } }
Các thành phần phần mềm trung gian tạo thành một đường ống xử lý các yêu cầu và phản hồi. Phần mềm trung gian tùy chỉnh có thể được tạo cho các mối quan tâm xuyên suốt như ghi nhật ký hoặc xử lý lỗi.
app.Use(async (context, next) => { // Custom logic before passing to the next middleware await next(); // Custom logic after executing the next middleware });
Định tuyến trong .NET Web API đạt được thông qua định tuyến thuộc tính trên bộ điều khiển và phương thức hành động. Điều này cho phép các URL được ánh xạ trực tiếp tới các hành động của bộ điều khiển.
[HttpGet("myaction/{id}")] public IActionResult GetAction(int id) => Ok($"Action with ID = {id}");
Liên kết mô hình tự động ánh xạ dữ liệu từ các yêu cầu HTTP tới các tham số phương thức hành động. Nó hỗ trợ các loại phức tạp, bao gồm nội dung JSON và tham số chuỗi truy vấn.
public class MyModel { public int Id { get; set; } public string Name { get; set; } } [HttpPost] public IActionResult PostAction([FromBody] MyModel model) => Ok(model);
Chú thích dữ liệu có thể được sử dụng để xác thực dữ liệu mô hình. Thuộc tính [ApiController] tự động thực thi xác thực, phản hồi bằng 400 nếu mô hình không hợp lệ.
public class MyModel { [Required] public int Id { get; set; } [StringLength(100)] public string Name { get; set; } }
Các hành động không đồng bộ cải thiện khả năng mở rộng bằng cách giải phóng các luồng trong khi chờ các thao tác I/O hoàn tất. Sử dụng từ khóa async và trả về Tác vụ hoặc Tác vụ<IActionResult>.
[HttpGet("{id}")] public async Task<IActionResult> GetAsync(int id) { var result = await _service.GetByIdAsync(id); return Ok(result); }
Xử lý ngoại lệ toàn cầu cho phép xử lý lỗi tập trung, ghi nhật ký và phản hồi API được tiêu chuẩn hóa đối với các ngoại lệ chưa được xử lý.
app.UseExceptionHandler(a => a.Run(async context => { var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>(); var exception = exceptionHandlerPathFeature.Error; // Log the exception, generate a custom response, etc. context.Response.StatusCode = 500; await context.Response.WriteAsJsonAsync(new { Error = "An unexpected error occurred" }); }));
Lập phiên bản API giúp quản lý các thay đổi đối với API theo thời gian. Nền tảng .NET hỗ trợ tạo phiên bản thông qua chuỗi truy vấn, đường dẫn URL hoặc tiêu đề yêu cầu.
builder.Services.AddApiVersioning(options => { options.AssumeDefaultVersionWhenUnspecified = true; options.DefaultApiVersion = new ApiVersion(1, 0); options.ReportApiVersions = true; });
Đàm phán nội dung cho phép API phân phát các định dạng phản hồi khác nhau dựa trên tiêu đề Chấp nhận trong yêu cầu, cho phép hỗ trợ các định dạng như JSON, XML, v.v.
builder.Services.AddControllers() .AddXmlDataContractSerializerFormatters();
Tùy chỉnh định dạng phản hồi JSON, chẳng hạn như đặt tên CamelCase hoặc bỏ qua các giá trị null, bằng cách định cấu hình cài đặt trình tuần tự hóa JSON.
builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; options.JsonSerializerOptions.IgnoreNullValues = true; });
Chia sẻ tài nguyên giữa các nguồn gốc (CORS) cho phép API của bạn được gọi từ các ứng dụng web được lưu trữ trên các miền khác nhau. Định cấu hình chính sách CORS theo yêu cầu của bạn.
builder.Services.AddCors(options => { options.AddPolicy("AllowSpecificOrigin", builder => builder.WithOrigins("http://example.com")); }); app.UseCors("AllowSpecificOrigin");
Bảo mật API của bạn bằng cách bật xác thực, xác minh danh tính của người dùng hoặc dịch vụ đưa ra yêu cầu.
builder.Services.AddAuthentication("Bearer") .AddJwtBearer(options => { options.Authority = "https://your-auth-server"; options.Audience = "your-api"; });
Sau khi xác thực, ủy quyền sẽ xác định xem người dùng được xác thực có quyền thực hiện một hành động hoặc truy cập tài nguyên hay không.
[Authorize] public class SecureController : ControllerBase { // Action methods here }
Swagger (OpenAPI) cung cấp tài liệu tương tác cho API của bạn, cho phép các nhà phát triển hiểu và sử dụng nó một cách dễ dàng.
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); app.UseSwagger(); app.UseSwaggerUI();
.NET Core cung cấp một khung ghi nhật ký tích hợp có thể ghi nhật ký các thông báo đến nhiều đầu ra khác nhau (bảng điều khiển, cửa sổ gỡ lỗi, dịch vụ bên ngoài, v.v.).
logger.LogInformation("This is an informational message"); app.Use(async (context, next) => { logger.LogError("This is an error message before the next middleware"); await next.Invoke(); // Log after calling the next middleware });
Entity Framework Core là ORM được sử dụng để truy cập dữ liệu trong các ứng dụng .NET. Nó cho phép bạn truy vấn và thao tác dữ liệu bằng cách sử dụng các đối tượng được gõ mạnh.
public class MyDbContext : DbContext { public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) {} public DbSet<MyModel> MyModels { get; set; } }
Quá trình di chuyển cho phép bạn áp dụng kiểm soát phiên bản cho lược đồ cơ sở dữ liệu bằng cách theo dõi các thay đổi trong mô hình dữ liệu của bạn.
dotnet ef migrations add InitialCreate dotnet ef database update
Mẫu Kho lưu trữ trừu tượng hóa lớp dữ liệu, làm cho ứng dụng của bạn trở nên mô-đun hơn và dễ bảo trì hơn.
public interface IRepository<T> { Task<IEnumerable<T>> GetAllAsync(); Task<T> GetByIdAsync(int id); // Other methods... } public class MyRepository<T> : IRepository<T> where T : class { private readonly MyDbContext _context; public MyRepository(MyDbContext context) { _context = context; } // Implement methods... }
Kiểm tra đơn vị đảm bảo API Web của bạn hoạt động chính xác bằng cách kiểm tra từng đơn vị mã riêng lẻ.
public class MyControllerTests { [Fact] public async Task Get_ReturnsExpectedValue() { // Arrange var serviceMock = new Mock<IMyService>(); serviceMock.Setup(service => service.GetAsync()).ReturnsAsync("test"); var controller = new MyController(serviceMock.Object); // Act var result = await controller.Get(); // Assert Assert.Equal("test", result.Value); } }
.NET Web API có thể đóng vai trò là phần phụ trợ cho ứng dụng giao diện người dùng, cung cấp các dịch vụ RESTful.
fetch('https://localhost:5001/mycontroller') .then(response => response.json()) .then(data => console.log(data));
Kiểm tra tình trạng cung cấp một cách để theo dõi trạng thái ứng dụng của bạn và các phần phụ thuộc của nó, hữu ích cho kiến trúc vi dịch vụ.
builder.Services.AddHealthChecks(); app.MapHealthChecks("/health");
SignalR kích hoạt chức năng web theo thời gian thực, cho phép mã phía máy chủ gửi thông báo không đồng bộ đến các ứng dụng web phía máy khách.
public class MyHub : Hub { public async Task SendMessage(string user, string message) { await Clients.All.SendAsync("ReceiveMessage", user, message); } }
Bộ nhớ đệm phản hồi giúp giảm số lượng yêu cầu mà máy chủ phải xử lý bằng cách lưu trữ bản sao của các tài nguyên được yêu cầu trước đó.
[HttpGet("{id}")] [ResponseCache(Duration = 60)] public IActionResult GetById(int id) { // Retrieve and return your resource }
Việc cung cấp các tệp tĩnh (HTML, CSS, JavaScript, v.v.) là điều cần thiết để sao lưu các ứng dụng giao diện người dùng bằng API Web .NET.
app.UseStaticFiles(); // Enable static file serving
Mẫu tùy chọn sử dụng các lớp để thể hiện các nhóm cài đặt liên quan. Sử dụng IOptions<T>, bạn có thể truy cập các cài đặt này ở bất kỳ đâu trong ứng dụng của mình.
public class MySettings { public string Setting1 { get; set; } // Other settings } builder.Services.Configure<MySettings>(builder.Configuration.GetSection("MySettings")); public class MyService { private readonly MySettings _settings; public MyService(IOptions<MySettings> settings) { _settings = settings.Value; } // Use _settings.Setting1 }
Middleware là phần mềm được tập hợp thành một hệ thống ứng dụng để xử lý các yêu cầu và phản hồi. Phần mềm trung gian tùy chỉnh có thể được tạo để thực hiện các tác vụ cụ thể.
public class MyCustomMiddleware { private readonly RequestDelegate _next; public MyCustomMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext httpContext) { // Pre-processing logic here await _next(httpContext); // Call the next middleware in the pipeline // Post-processing logic here } } // Extension method for easy middleware registration public static class MyCustomMiddlewareExtensions { public static IApplicationBuilder UseMyCustomMiddleware(this IApplicationBuilder builder) { return builder.UseMiddleware<MyCustomMiddleware>(); } }
Giới hạn tỷ lệ bảo vệ API của bạn khỏi bị sử dụng quá mức bằng cách giới hạn tần suất người dùng có thể thực hiện yêu cầu trong một khung thời gian nhất định.
// Assume using a third-party library like AspNetCoreRateLimit builder.Services.AddInMemoryRateLimiting(); builder.Services.Configure<IpRateLimitOptions>(options => { options.GeneralRules = new List<RateLimitRule> { new RateLimitRule { Endpoint = "*", Limit = 100, Period = "1h" } }; });
Khóa API là một cách đơn giản để xác thực và ủy quyền các lệnh gọi API. Chúng được chuyển từ máy khách này sang máy chủ khác trong chuỗi truy vấn hoặc tiêu đề.
public class ApiKeyMiddleware { private readonly RequestDelegate _next; private const string APIKEYNAME = "x-api-key"; public ApiKeyMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { if (!context.Request.Headers.TryGetValue(APIKEYNAME, out var extractedApiKey)) { context.Response.StatusCode = 401; await context.Response.WriteAsync("API Key was not provided."); return; } // Validate the extracted API Key here... await _next(context); } }
Bộ nhớ đệm đầu ra cho phép bạn lưu trữ phản hồi cho một yêu cầu. Các yêu cầu tiếp theo có thể được phục vụ từ bộ đệm, cải thiện đáng kể hiệu suất.
[HttpGet] [ResponseCache(Duration = 120, Location = ResponseCacheLocation.Client, NoStore = false)] public IActionResult Get() { // Your logic here }
Tác vụ nền cho phép các hoạt động chạy ở chế độ nền, độc lập với yêu cầu của người dùng, như gửi email hoặc xử lý các công việc chạy trong thời gian dài.
public class MyBackgroundService : BackgroundService { protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { // Your background task logic here await Task.Delay(TimeSpan.FromHours(1), stoppingToken); } } }
WebSockets cung cấp kênh liên lạc song công hoàn toàn qua một kết nối lâu dài, lý tưởng cho các ứng dụng thời gian thực.
app.UseWebSockets(); app.Use(async (context, next) => { if (context.WebSockets.IsWebSocketRequest) { WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync(); // Handle the WebSocket request here } else { await next(); } });
Bản địa hóa yêu cầu cung cấp cách bản địa hóa nội dung cho các nền văn hóa và ngôn ngữ khác nhau, dựa trên thông tin của yêu cầu.
var supportedCultures = new[] { "en-US", "fr-FR" }; var localizationOptions = new RequestLocalizationOptions() .SetDefaultCulture(supportedCultures[0]) .AddSupportedCultures(supportedCultures) .AddSupportedUICultures(supportedCultures); app.UseRequestLocalization(localizationOptions);
GraphQL là ngôn ngữ truy vấn dành cho API. Việc tích hợp API Web .NET với GraphQL cho phép truy xuất dữ liệu hiệu quả hơn.
// Assume using a library like HotChocolate builder.Services .AddGraphQLServer() .AddQueryType<Query>(); app.MapGraphQL();
Giám sát và đo từ xa liên quan đến việc thu thập, phân tích và hành động dựa trên dữ liệu về hiệu suất và cách sử dụng ứng dụng của bạn.
// Assume using Application Insights builder.Services.AddApplicationInsightsTelemetry("YOUR_INSTRUMENTATION_KEY");
SignalR là thư viện giúp đơn giản hóa việc thêm chức năng web thời gian thực vào ứng dụng. Chức năng web thời gian thực là khả năng yêu cầu mã máy chủ đẩy nội dung đến các máy khách được kết nối ngay lập tức khi nó xảy ra, không yêu cầu máy chủ phải đợi máy khách yêu cầu dữ liệu mới. SignalR hoàn hảo để phát triển các ứng dụng trò chuyện, bảng điều khiển thời gian thực và nhiều ứng dụng web tương tác hơn.
public class ChatHub : Hub { public async Task SendMessage(string user, string message) { // Call the broadcastMessage method to update clients. await Clients.All.SendAsync("broadcastMessage", user, message); } } // Startup or Program.cs app.MapHub<ChatHub>("/chathub");
Tích hợp trong Program.cs:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // Other configurations... app.UseEndpoints(endpoints => { endpoints.MapHub<ChatHub>("/chathub"); }); }
Entity Framework Core cho phép ánh xạ các mối quan hệ phức tạp giữa các thực thể, chẳng hạn như một-một, một-nhiều và nhiều-nhiều.
public class Author { public int AuthorId { get; set; } public string Name { get; set; } public ICollection<Book> Books { get; set; } } public class Book { public int BookId { get; set; } public string Title { get; set; } public int AuthorId { get; set; } public Author Author { get; set; } }
Các thuộc tính xác thực tùy chỉnh cho phép bạn xác định logic xác thực của mình cho các mô hình dữ liệu, mở rộng các thuộc tính xác thực tích hợp sẵn.
public class MyCustomValidationAttribute : ValidationAttribute { protected override ValidationResult IsValid(object value, ValidationContext validationContext) { // Your custom validation logic here if (value is int intValue && intValue > 0) { return ValidationResult.Success; } return new ValidationResult("Value must be positive"); } } public class MyModel { [MyCustomValidationAttribute] public int MyProperty { get; set; } }
Mẫu tùy chọn của .NET hỗ trợ các kịch bản cấu hình phức tạp, bao gồm các đối tượng lồng nhau, danh sách và xác thực.
public class MyOptions { public MyNestedOptions Nested { get; set; } public List<string> Items { get; set; } } public class MyNestedOptions { public string Key { get; set; } } // In Program.cs or Startup.cs builder.Services.Configure<MyOptions>(builder.Configuration.GetSection("MyOptions"));
Giám sát và lập hồ sơ ứng dụng có thể xác định các điểm nghẽn và sự kém hiệu quả, điều cần thiết để tối ưu hóa hiệu suất.
app.UseMiniProfiler();
Nâng cao tài liệu API của bạn bằng cách tích hợp nhận xét XML vào giao diện người dùng Swagger của bạn, mang lại trải nghiệm phong phú hơn cho các nhà phát triển sử dụng API của bạn.
builder.Services.AddSwaggerGen(c => { var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); c.IncludeXmlComments(xmlPath); });
Toàn cầu hóa và bản địa hóa cho phép ứng dụng của bạn hỗ trợ nhiều ngôn ngữ và văn hóa, giúp khán giả toàn cầu có thể truy cập ứng dụng đó.
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); app.UseRequestLocalization(app.Services.GetRequiredService<IOptions<RequestLocalizationOptions>>().Value);
Cải thiện tính bảo mật của ứng dụng web của bạn bằng cách thêm các tiêu đề HTTP khác nhau có thể bảo vệ khỏi các cuộc tấn công và lỗ hổng phổ biến.
app.UseHsts(); app.UseXContentTypeOptions(); app.UseReferrerPolicy(opts => opts.NoReferrer()); app.UseXXssProtection(options => options.EnabledWithBlockMode()); app.UseXfo(options => options.Deny());
Cờ tính năng cho phép bạn bật và tắt các tính năng của ứng dụng mà không cần triển khai mã mới, tạo điều kiện cho việc thử nghiệm và triển khai dễ dàng hơn.
// Using a library like Microsoft.FeatureManagement builder.Services.AddFeatureManagement();
Blazor cho phép bạn xây dựng giao diện người dùng web tương tác bằng C# thay vì JavaScript. Việc tích hợp Blazor với API Web mang lại trải nghiệm phát triển toàn diện liền mạch.
// In a Blazor Server app @code { private IEnumerable<WeatherForecast> forecasts; protected override async Task OnInitializedAsync() { forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast"); } }
Tính năng nén phản hồi có thể giảm kích thước phản hồi API của bạn, cải thiện thời gian tải cho khách hàng qua mạng chậm.
builder.Services.AddResponseCompression(options => { options.Providers.Add<GzipCompressionProvider>(); options.EnableForHttps = true; }); app.UseResponseCompression();
Cảm ơn bạn đã là thành viên của cộng đồng C#! Trước khi bạn đi:
Theo dõi chúng tôi: X | LinkedIn | Dev.to | Nút băm | Bản tin | tumblr
Truy cập các nền tảng khác của chúng tôi: GitHub | Instagram | Tiktok | Quora | Daily.dev
Cũng được xuất bản ở đây