Von der ersten Projekteinrichtung mit der .NET-CLI bis zur Konfiguration von Middleware, Controllern und Diensten lernen Sie jeden Schritt zum Aufbau einer robusten API. Entdecken Sie Best Practices für die Abhängigkeitsinjektion, asynchrone Aktionen und die Behandlung von Ausnahmen, um skalierbare, effiziente Webanwendungen zu erstellen.
Verwenden Sie die .NET-CLI, um ein neues Web-API-Projekt zu erstellen. Dadurch wird eine grundlegende Projektstruktur eingerichtet, einschließlich Program.cs für den Start und eines WeatherForecast-Controllers als Beispiel.
dotnet new webapi -n MyWebApi
.NET 8 setzt den Trend zu minimalen APIs fort und ermöglicht Ihnen die einfache und übersichtliche Konfiguration von Diensten und Endpunkten direkt in der Datei Program.cs.
var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapGet("/", () => "Hello, World!"); app.Run();
Controller verarbeiten eingehende HTTP-Anfragen und antworten dem Client. Sie werden durch Erben von ControllerBase und Annotieren mit [ApiController] definiert.
[ApiController] [Route("[controller]")] public class MyController : ControllerBase { [HttpGet] public IActionResult Get() => Ok("Hello from MyController"); }
Die integrierte Abhängigkeitsinjektion (DI) von .NET Core erleichtert die Verwaltung von Abhängigkeiten. Sie können Dienste über deren Konstruktoren in Ihre Controller einschleusen.
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()); }
Dienste (wie Datenbankkontexte, benutzerdefinierte Dienste usw.) werden in der Datei „Program.cs“ konfiguriert, sodass sie für die Abhängigkeitsinjektion in Ihrer gesamten Anwendung verfügbar sind.
builder.Services.AddScoped<MyService>();
.NET unterstützt umgebungsspezifische Konfigurationsdateien (appsettings.json, appsettings.Development.json usw.) und ermöglicht so unterschiedliche Einstellungen je nach Anwendungsumgebung.
// appsettings.Development.json { "Logging": { "LogLevel": { "Default": "Debug" } } }
Middleware-Komponenten bilden eine Pipeline, die Anfragen und Antworten verarbeitet. Für übergreifende Anliegen wie Protokollierung oder Fehlerbehandlung kann benutzerdefinierte Middleware erstellt werden.
app.Use(async (context, next) => { // Custom logic before passing to the next middleware await next(); // Custom logic after executing the next middleware });
Das Routing in der .NET-Web-API wird durch Attributrouting auf Controllern und Aktionsmethoden erreicht. Dadurch können URLs direkt Controller-Aktionen zugeordnet werden.
[HttpGet("myaction/{id}")] public IActionResult GetAction(int id) => Ok($"Action with ID = {id}");
Die Modellbindung ordnet Daten aus HTTP-Anfragen automatisch Aktionsmethodenparametern zu. Es unterstützt komplexe Typen, einschließlich JSON-Körper und Abfragezeichenfolgenparameter.
public class MyModel { public int Id { get; set; } public string Name { get; set; } } [HttpPost] public IActionResult PostAction([FromBody] MyModel model) => Ok(model);
Datenanmerkungen können zur Validierung von Modelldaten verwendet werden. Das [ApiController]-Attribut erzwingt automatisch die Validierung und antwortet mit 400, wenn das Modell ungültig ist.
public class MyModel { [Required] public int Id { get; set; } [StringLength(100)] public string Name { get; set; } }
Asynchrone Aktionen verbessern die Skalierbarkeit, indem sie Threads freigeben, während sie auf den Abschluss von E/A-Vorgängen warten. Verwenden Sie das Schlüsselwort async und geben Sie Task oder Task<IActionResult> zurück.
[HttpGet("{id}")] public async Task<IActionResult> GetAsync(int id) { var result = await _service.GetByIdAsync(id); return Ok(result); }
Die globale Ausnahmebehandlung ermöglicht eine zentralisierte Fehlerverarbeitung, Protokollierung und standardisierte API-Antworten auf nicht behandelte Ausnahmen.
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" }); }));
Die API-Versionierung hilft dabei, Änderungen an der API im Laufe der Zeit zu verwalten. Die .NET-Plattform unterstützt die Versionierung über Abfragezeichenfolge, URL-Pfad oder Anforderungsheader.
builder.Services.AddApiVersioning(options => { options.AssumeDefaultVersionWhenUnspecified = true; options.DefaultApiVersion = new ApiVersion(1, 0); options.ReportApiVersions = true; });
Durch die Inhaltsverhandlung kann eine API verschiedene Antwortformate basierend auf dem Accept-Header in der Anfrage bereitstellen und so Formate wie JSON, XML usw. unterstützen.
builder.Services.AddControllers() .AddXmlDataContractSerializerFormatters();
Passen Sie die JSON-Antwortformatierung an, z. B. die Benennung von CamelCase oder das Ignorieren von Nullwerten, indem Sie die JSON-Serialisierungseinstellungen konfigurieren.
builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; options.JsonSerializerOptions.IgnoreNullValues = true; });
Cross-Origin Resource Sharing (CORS) ermöglicht den Aufruf Ihrer API von Webanwendungen, die auf verschiedenen Domänen gehostet werden. Konfigurieren Sie die CORS-Richtlinie gemäß Ihren Anforderungen.
builder.Services.AddCors(options => { options.AddPolicy("AllowSpecificOrigin", builder => builder.WithOrigins("http://example.com")); }); app.UseCors("AllowSpecificOrigin");
Sichern Sie Ihre API, indem Sie die Authentifizierung aktivieren, die die Identität von Benutzern oder Diensten überprüft, die Anfragen stellen.
builder.Services.AddAuthentication("Bearer") .AddJwtBearer(options => { options.Authority = "https://your-auth-server"; options.Audience = "your-api"; });
Nach der Authentifizierung bestimmt die Autorisierung, ob ein authentifizierter Benutzer berechtigt ist, eine Aktion auszuführen oder auf eine Ressource zuzugreifen.
[Authorize] public class SecureController : ControllerBase { // Action methods here }
Swagger (OpenAPI) bietet interaktive Dokumentation für Ihre API, sodass Entwickler sie leicht verstehen und nutzen können.
builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); app.UseSwagger(); app.UseSwaggerUI();
.NET Core bietet ein integriertes Protokollierungsframework, das Nachrichten an verschiedenen Ausgaben (Konsole, Debug-Fenster, externe Dienste usw.) protokollieren kann.
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 ist ein ORM, das für den Datenzugriff in .NET-Anwendungen verwendet wird. Es ermöglicht Ihnen, Daten mithilfe stark typisierter Objekte abzufragen und zu bearbeiten.
public class MyDbContext : DbContext { public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) {} public DbSet<MyModel> MyModels { get; set; } }
Mit Migrationen können Sie die Versionskontrolle auf Ihr Datenbankschema anwenden, indem Sie Änderungen in Ihren Datenmodellen verfolgen.
dotnet ef migrations add InitialCreate dotnet ef database update
Das Repository-Muster abstrahiert die Datenschicht und macht Ihre Anwendung modularer und einfacher zu warten.
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... }
Unit-Tests stellen sicher, dass Ihre Web-API ordnungsgemäß funktioniert, indem einzelne Codeeinheiten isoliert getestet werden.
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); } }
Die .NET-Web-API kann als Backend für eine Front-End-Anwendung dienen und RESTful-Dienste bereitstellen.
fetch('https://localhost:5001/mycontroller') .then(response => response.json()) .then(data => console.log(data));
Gesundheitsprüfungen bieten eine Möglichkeit, den Status Ihrer Anwendung und ihrer Abhängigkeiten zu überwachen, was für Microservices-Architekturen nützlich ist.
builder.Services.AddHealthChecks(); app.MapHealthChecks("/health");
SignalR ermöglicht Echtzeit-Webfunktionen, sodass serverseitiger Code asynchrone Benachrichtigungen an clientseitige Webanwendungen senden kann.
public class MyHub : Hub { public async Task SendMessage(string user, string message) { await Clients.All.SendAsync("ReceiveMessage", user, message); } }
Das Zwischenspeichern von Antworten reduziert die Anzahl der Anfragen, die ein Server bearbeiten muss, indem eine Kopie der zuvor angeforderten Ressourcen gespeichert wird.
[HttpGet("{id}")] [ResponseCache(Duration = 60)] public IActionResult GetById(int id) { // Retrieve and return your resource }
Die Bereitstellung statischer Dateien (HTML, CSS, JavaScript usw.) ist für die Unterstützung von Front-End-Anwendungen mit einer .NET-Web-API unerlässlich.
app.UseStaticFiles(); // Enable static file serving
Das Optionsmuster verwendet Klassen, um Gruppen verwandter Einstellungen darzustellen. Mit IOptions<T> können Sie überall in Ihrer Anwendung auf diese Einstellungen zugreifen.
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 ist Software, die in eine Anwendungspipeline integriert wird, um Anfragen und Antworten zu verarbeiten. Zur Ausführung bestimmter Aufgaben kann benutzerdefinierte Middleware erstellt werden.
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>(); } }
Die Ratenbegrenzung schützt Ihre API vor Überbeanspruchung, indem sie begrenzt, wie oft ein Benutzer innerhalb eines bestimmten Zeitraums Anfragen stellen kann.
// 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-Schlüssel sind eine einfache Möglichkeit, API-Aufrufe zu authentifizieren und zu autorisieren. Sie werden entweder in der Abfragezeichenfolge oder im Header vom Client an den Server übergeben.
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); } }
Mit dem Ausgabe-Caching können Sie die Antwort auf eine Anfrage speichern. Nachfolgende Anfragen können aus dem Cache bedient werden, was die Leistung erheblich verbessert.
[HttpGet] [ResponseCache(Duration = 120, Location = ResponseCacheLocation.Client, NoStore = false)] public IActionResult Get() { // Your logic here }
Hintergrundaufgaben ermöglichen die Ausführung von Vorgängen im Hintergrund, unabhängig von Benutzeranfragen, wie z. B. dem Senden von E-Mails oder der Verarbeitung lang laufender Aufträge.
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 bieten einen Vollduplex-Kommunikationskanal über eine einzige, langlebige Verbindung, ideal für Echtzeitanwendungen.
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(); } });
Die Anforderungslokalisierung bietet eine Möglichkeit, Inhalte für verschiedene Kulturen und Sprachen basierend auf den Informationen der Anforderung zu lokalisieren.
var supportedCultures = new[] { "en-US", "fr-FR" }; var localizationOptions = new RequestLocalizationOptions() .SetDefaultCulture(supportedCultures[0]) .AddSupportedCultures(supportedCultures) .AddSupportedUICultures(supportedCultures); app.UseRequestLocalization(localizationOptions);
GraphQL ist eine Abfragesprache für APIs. Die Integration einer .NET-Web-API mit GraphQL ermöglicht einen effizienteren Datenabruf.
// Assume using a library like HotChocolate builder.Services .AddGraphQLServer() .AddQueryType<Query>(); app.MapGraphQL();
Überwachung und Telemetrie umfassen das Sammeln, Analysieren und Reagieren auf Daten über die Leistung und Nutzung Ihrer Anwendung.
// Assume using Application Insights builder.Services.AddApplicationInsightsTelemetry("YOUR_INSTRUMENTATION_KEY");
SignalR ist eine Bibliothek, die das Hinzufügen von Echtzeit-Webfunktionen zu Apps vereinfacht. Echtzeit-Webfunktionalität ist die Möglichkeit, dass Servercode Inhalte sofort an verbundene Clients weiterleitet, ohne dass der Server darauf warten muss, dass ein Client neue Daten anfordert. SignalR eignet sich perfekt für die Entwicklung von Chat-Anwendungen, Echtzeit-Dashboards und interaktiveren Webanwendungen.
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");
Integration in Program.cs:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // Other configurations... app.UseEndpoints(endpoints => { endpoints.MapHub<ChatHub>("/chathub"); }); }
Entity Framework Core ermöglicht die Abbildung komplexer Beziehungen zwischen Entitäten, z. B. Eins-zu-Eins, Eins-zu-Viele und Viele-zu-Viele.
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; } }
Mit benutzerdefinierten Validierungsattributen können Sie Ihre Validierungslogik für Datenmodelle definieren und die integrierten Validierungsattribute erweitern.
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; } }
Das Optionsmuster von .NET unterstützt komplexe Konfigurationsszenarien, einschließlich verschachtelter Objekte, Listen und Validierung.
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"));
Durch die Überwachung und Profilierung einer Anwendung können Engpässe und Ineffizienzen identifiziert werden, was für die Optimierung der Leistung unerlässlich ist.
app.UseMiniProfiler();
Erweitern Sie Ihre API-Dokumentation, indem Sie XML-Kommentare in Ihre Swagger-Benutzeroberfläche integrieren und so Entwicklern, die Ihre API nutzen, ein umfassenderes Erlebnis bieten.
builder.Services.AddSwaggerGen(c => { var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); c.IncludeXmlComments(xmlPath); });
Globalisierung und Lokalisierung ermöglichen es Ihrer Anwendung, mehrere Sprachen und Kulturen zu unterstützen und sie so einem globalen Publikum zugänglich zu machen.
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); app.UseRequestLocalization(app.Services.GetRequiredService<IOptions<RequestLocalizationOptions>>().Value);
Die Verbesserung der Sicherheit Ihrer Webanwendung durch das Hinzufügen verschiedener HTTP-Header kann Sie vor häufigen Angriffen und Schwachstellen schützen.
app.UseHsts(); app.UseXContentTypeOptions(); app.UseReferrerPolicy(opts => opts.NoReferrer()); app.UseXXssProtection(options => options.EnabledWithBlockMode()); app.UseXfo(options => options.Deny());
Mit Feature-Flags können Sie Funktionen Ihrer Anwendung ein- und ausschalten, ohne neuen Code bereitzustellen, was einfachere Tests und Rollouts ermöglicht.
// Using a library like Microsoft.FeatureManagement builder.Services.AddFeatureManagement();
Mit Blazor können Sie interaktive Web-Benutzeroberflächen mit C# anstelle von JavaScript erstellen. Die Integration von Blazor mit der Web-API bietet ein nahtloses Full-Stack-Entwicklungserlebnis.
// In a Blazor Server app @code { private IEnumerable<WeatherForecast> forecasts; protected override async Task OnInitializedAsync() { forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast"); } }
Die Antwortkomprimierung kann die Größe Ihrer API-Antworten reduzieren und so die Ladezeiten für Clients über langsame Netzwerke verbessern.
builder.Services.AddResponseCompression(options => { options.Providers.Add<GzipCompressionProvider>(); options.EnableForHttps = true; }); app.UseResponseCompression();
Vielen Dank, dass Sie Teil der C#-Community sind! Bevor Sie gehen:
Folgen Sie uns: X | LinkedIn | Dev.to | Hashnode | Newsletter | Tumblr
Besuchen Sie unsere anderen Plattformen: GitHub | Instagram | Tiktok | Quora | Daily.dev
Auch hier veröffentlicht