从使用 .NET CLI 进行初始项目设置到配置中间件、控制器和服务,了解构建强大 API 的每一步。发现依赖注入、异步操作和处理异常的最佳实践,以创建可扩展、高效的 Web 应用程序。
使用 .NET CLI 创建新的 Web API 项目。这设置了一个基本的项目结构,包括用于启动的 Program.cs 和作为示例的 WeatherForecast 控制器。
dotnet new webapi -n MyWebApi
.NET 8 延续了最少 API 的趋势,允许您直接在 Program.cs 文件中以简化且简洁的方式配置服务和端点。
var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapGet("/", () => "Hello, World!"); app.Run();
控制器处理传入的 HTTP 请求并响应客户端。它们是通过继承ControllerBase并用[ApiController]注释来定义的。
[ApiController] [Route("[controller]")] public class MyController : ControllerBase { [HttpGet] public IActionResult Get() => Ok("Hello from MyController"); }
.NET Core 的内置依赖项注入 (DI) 可以轻松管理依赖项。您可以通过控制器的构造函数将服务注入到控制器中。
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()); }
服务(如数据库上下文、自定义服务等)在 Program.cs 文件中配置,使它们可用于整个应用程序的依赖项注入。
builder.Services.AddScoped<MyService>();
.NET 支持特定于环境的配置文件(appsettings.json、appsettings.Development.json 等),允许根据应用程序的环境进行不同的设置。
// appsettings.Development.json { "Logging": { "LogLevel": { "Default": "Debug" } } }
中间件组件形成处理请求和响应的管道。可以为日志记录或错误处理等横切问题创建自定义中间件。
app.Use(async (context, next) => { // Custom logic before passing to the next middleware await next(); // Custom logic after executing the next middleware });
.NET Web API 中的路由是通过控制器和操作方法上的属性路由来实现的。这允许 URL 直接映射到控制器操作。
[HttpGet("myaction/{id}")] public IActionResult GetAction(int id) => Ok($"Action with ID = {id}");
模型绑定自动将 HTTP 请求中的数据映射到操作方法参数。它支持复杂类型,包括 JSON 主体和查询字符串参数。
public class MyModel { public int Id { get; set; } public string Name { get; set; } } [HttpPost] public IActionResult PostAction([FromBody] MyModel model) => Ok(model);
数据注释可用于验证模型数据。 [ApiController] 属性自动强制验证,如果模型无效,则响应 400。
public class MyModel { [Required] public int Id { get; set; } [StringLength(100)] public string Name { get; set; } }
异步操作通过在等待 I/O 操作完成时释放线程来提高可伸缩性。使用 async 关键字,并返回 Task 或 Task<IActionResult>。
[HttpGet("{id}")] public async Task<IActionResult> GetAsync(int id) { var result = await _service.GetByIdAsync(id); return Ok(result); }
全局异常处理允许对未处理的异常进行集中错误处理、日志记录和标准化 API 响应。
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" }); }));
API 版本控制有助于管理 API 随着时间的推移而发生的更改。 .NET 平台支持通过查询字符串、URL 路径或请求标头进行版本控制。
builder.Services.AddApiVersioning(options => { options.AssumeDefaultVersionWhenUnspecified = true; options.DefaultApiVersion = new ApiVersion(1, 0); options.ReportApiVersions = true; });
内容协商允许 API 根据请求中的 Accept 标头提供不同格式的响应,从而支持 JSON、XML 等格式。
builder.Services.AddControllers() .AddXmlDataContractSerializerFormatters();
通过配置 JSON 序列化程序设置来自定义 JSON 响应格式,例如驼峰命名或忽略空值。
builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; options.JsonSerializerOptions.IgnoreNullValues = true; });
跨源资源共享 (CORS) 允许从不同域上托管的 Web 应用程序调用您的 API。根据您的要求配置 CORS 策略。
builder.Services.AddCors(options => { options.AddPolicy("AllowSpecificOrigin", builder => builder.WithOrigins("http://example.com")); }); app.UseCors("AllowSpecificOrigin");
通过启用身份验证来保护您的 API,该身份验证验证发出请求的用户或服务的身份。
builder.Services.AddAuthentication("Bearer") .AddJwtBearer(options => { options.Authority = "https://your-auth-server"; options.Audience = "your-api"; });
身份验证后,授权确定经过身份验证的用户是否有权执行操作或访问资源。
[Authorize] public class SecureController : ControllerBase { // Action methods here }
Swagger (OpenAPI) 为您的 API 提供交互式文档,使开发人员能够轻松理解和使用它。
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); app.UseSwagger(); app.UseSwaggerUI();
.NET Core 提供了一个内置的日志记录框架,可以将消息记录到各种输出(控制台、调试窗口、外部服务等)。
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 是一种用于 .NET 应用程序中数据访问的 ORM。它允许您使用强类型对象查询和操作数据。
public class MyDbContext : DbContext { public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) {} public DbSet<MyModel> MyModels { get; set; } }
迁移允许您通过跟踪数据模型中的更改来将版本控制应用于数据库架构。
dotnet ef migrations add InitialCreate dotnet ef database update
存储库模式抽象了数据层,使您的应用程序更加模块化并且更易于维护。
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... }
单元测试通过单独测试各个代码单元来确保您的 Web API 正常运行。
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可以作为前端应用程序的后端,提供RESTful服务。
fetch('https://localhost:5001/mycontroller') .then(response => response.json()) .then(data => console.log(data));
运行状况检查提供了一种监视应用程序及其依赖项的状态的方法,这对于微服务架构非常有用。
builder.Services.AddHealthChecks(); app.MapHealthChecks("/health");
SignalR 支持实时 Web 功能,允许服务器端代码向客户端 Web 应用程序发送异步通知。
public class MyHub : Hub { public async Task SendMessage(string user, string message) { await Clients.All.SendAsync("ReceiveMessage", user, message); } }
响应缓存通过存储先前请求的资源的副本来减少服务器必须处理的请求数量。
[HttpGet("{id}")] [ResponseCache(Duration = 60)] public IActionResult GetById(int id) { // Retrieve and return your resource }
提供静态文件(HTML、CSS、JavaScript 等)对于使用 .NET Web API 支持前端应用程序至关重要。
app.UseStaticFiles(); // Enable static file serving
选项模式使用类来表示相关设置组。使用 IOptions<T>,您可以在应用程序中的任何位置访问这些设置。
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 }
中间件是组装到应用程序管道中以处理请求和响应的软件。可以创建自定义中间件来执行特定任务。
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>(); } }
速率限制通过限制用户在特定时间范围内发出请求的频率来保护您的 API 免遭过度使用。
// 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" } }; });
API 密钥是一种验证和授权 API 调用的简单方法。它们通过查询字符串或标头从客户端传递到服务器。
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); } }
输出缓存允许您存储对请求的响应。后续请求可以从缓存中得到服务,从而显着提高性能。
[HttpGet] [ResponseCache(Duration = 120, Location = ResponseCacheLocation.Client, NoStore = false)] public IActionResult Get() { // Your logic here }
后台任务使操作能够在后台运行,独立于用户请求,例如发送电子邮件或处理长时间运行的作业。
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); } } }
WebSocket 通过单个长期连接提供全双工通信通道,非常适合实时应用程序。
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(); } });
请求本地化提供了一种根据请求信息针对不同文化和语言本地化内容的方法。
var supportedCultures = new[] { "en-US", "fr-FR" }; var localizationOptions = new RequestLocalizationOptions() .SetDefaultCulture(supportedCultures[0]) .AddSupportedCultures(supportedCultures) .AddSupportedUICultures(supportedCultures); app.UseRequestLocalization(localizationOptions);
GraphQL 是一种 API 查询语言。将 .NET Web API 与 GraphQL 集成可以实现更高效的数据检索。
// Assume using a library like HotChocolate builder.Services .AddGraphQLServer() .AddQueryType<Query>(); app.MapGraphQL();
监视和遥测涉及收集、分析有关应用程序性能和使用情况的数据并对其采取行动。
// Assume using Application Insights builder.Services.AddApplicationInsightsTelemetry("YOUR_INSTRUMENTATION_KEY");
SignalR 是一个库,可简化向应用程序添加实时 Web 功能的过程。实时 Web 功能是指服务器代码能够在发生内容时立即将内容推送到连接的客户端,而不需要服务器等待客户端请求新数据。 SignalR 非常适合开发聊天应用程序、实时仪表板和更具交互性的 Web 应用程序。
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");
集成到 Program.cs 中:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // Other configurations... app.UseEndpoints(endpoints => { endpoints.MapHub<ChatHub>("/chathub"); }); }
Entity Framework Core 允许映射实体之间的复杂关系,例如一对一、一对多和多对多。
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; } }
自定义验证属性允许您定义数据模型的验证逻辑,扩展内置验证属性。
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; } }
.NET 的选项模式支持复杂的配置方案,包括嵌套对象、列表和验证。
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"));
监视和分析应用程序可以识别瓶颈和低效率,这对于优化性能至关重要。
app.UseMiniProfiler();
通过将 XML 注释集成到 Swagger UI 中来增强 API 文档,为使用 API 的开发人员提供更丰富的体验。
builder.Services.AddSwaggerGen(c => { var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); c.IncludeXmlComments(xmlPath); });
全球化和本地化使您的应用程序能够支持多种语言和文化,使其可供全球受众使用。
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); app.UseRequestLocalization(app.Services.GetRequiredService<IOptions<RequestLocalizationOptions>>().Value);
通过添加各种 HTTP 标头来提高 Web 应用程序的安全性,可以防止常见的攻击和漏洞。
app.UseHsts(); app.UseXContentTypeOptions(); app.UseReferrerPolicy(opts => opts.NoReferrer()); app.UseXXssProtection(options => options.EnabledWithBlockMode()); app.UseXfo(options => options.Deny());
功能标志允许您在不部署新代码的情况下打开和关闭应用程序的功能,从而简化测试和部署。
// Using a library like Microsoft.FeatureManagement builder.Services.AddFeatureManagement();
Blazor 允许您使用 C# 而不是 JavaScript 构建交互式 Web UI。将 Blazor 与 Web API 集成可提供无缝的全栈开发体验。
// In a Blazor Server app @code { private IEnumerable<WeatherForecast> forecasts; protected override async Task OnInitializedAsync() { forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast"); } }
响应压缩可以减少 API 响应的大小,从而缩短客户端在慢速网络上的加载时间。
builder.Services.AddResponseCompression(options => { options.Providers.Add<GzipCompressionProvider>(); options.EnableForHttps = true; }); app.UseResponseCompression();
感谢您成为 C# 社区的一员!离开之前:
访问我们的其他平台: GitHub | Instagram |抖音|知乎|每日开发版
也发布在这里