Изучите каждый шаг создания надежного API — от первоначальной настройки проекта с использованием .NET CLI до настройки промежуточного программного обеспечения, контроллеров и служб. Ознакомьтесь с лучшими практиками внедрения зависимостей, асинхронных действий и обработки исключений для создания масштабируемых и эффективных веб-приложений.
Используйте .NET CLI для создания нового проекта веб-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"); }
Встроенная функция внедрения зависимостей (DI) .NET Core упрощает управление зависимостями. Вы можете внедрять сервисы в свои контроллеры через их конструкторы.
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 });
Маршрутизация в веб-API .NET осуществляется посредством маршрутизации атрибутов на контроллерах и методах действий. Это позволяет сопоставлять 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; } }
Асинхронные действия улучшают масштабируемость, освобождая потоки во время ожидания завершения операций ввода-вывода. Используйте ключевое слово 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, например именование в CamelCase или игнорирование нулевых значений, настроив параметры сериализатора JSON.
builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; options.JsonSerializerOptions.IgnoreNullValues = true; });
Совместное использование ресурсов между источниками (CORS) позволяет вызывать ваш 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 — это ORM, используемый для доступа к данным в приложениях .NET. Он позволяет запрашивать данные и манипулировать ими с использованием строго типизированных объектов.
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... }
Модульное тестирование обеспечивает правильную работу вашего веб-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); } }
Веб-API .NET может служить серверной частью внешнего приложения, предоставляя службы RESTful.
fetch('https://localhost:5001/mycontroller') .then(response => response.json()) .then(data => console.log(data));
Проверки работоспособности позволяют отслеживать состояние вашего приложения и его зависимостей, что полезно для архитектур микросервисов.
builder.Services.AddHealthChecks(); app.MapHealthChecks("/health");
SignalR обеспечивает веб-функциональность в режиме реального времени, позволяя серверному коду отправлять асинхронные уведомления клиентским веб-приложениям.
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 и т. д.) необходимо для поддержки интерфейсных приложений с помощью веб-API .NET.
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); } } }
WebSockets обеспечивают полнодуплексный канал связи через одно долговременное соединение, идеально подходящее для приложений реального времени.
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. Интеграция веб-API .NET с 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 — это библиотека, которая упрощает добавление веб-функций в реальном времени в приложения. Веб-функциональность в режиме реального времени — это возможность мгновенно передавать контент серверному коду подключенным клиентам, не требуя от сервера ждать, пока клиент запросит новые данные. SignalR идеально подходит для разработки приложений чата, информационных панелей реального времени и других интерактивных веб-приложений.
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();
Улучшите документацию по API, интегрировав XML-комментарии в пользовательский интерфейс Swagger, предоставляя более широкие возможности разработчикам, использующим ваш 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 может защитить от распространенных атак и уязвимостей.
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. Интеграция Blazor с веб-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#! Прежде чем ты уйдешь:
Следуйте за нами: X | LinkedIn | Dev.to | Хашнод | Информационный бюллетень | Тамблер
Посетите другие наши платформы: GitHub | Инстаграм | Тикток | Кора | Daily.dev
Также опубликовано здесь