Minimal APIs zijn een spannende functie geïntroduceerd in .NET 6, ontworpen om de manier waarop je APIs maakt te revolutioneren.
Stel je voor dat je robuuste APIs bouwt met minimaal code en geen boilerplate—geen gedoe meer met controllers, routing of middleware. Dat is wat minimal APIs je toestaan te doen. Het idee met deze APIs is om het ontwikkelingsproces te stroomlijnen, waardoor het uiterst eenvoudig en efficiënt wordt.
In dit artikel duiken we in de wereld van minimal APIs in .NET 8 en leiden we je door het proces van het maken van een volledig functionele boekwinkel API. Je leert hoe je alle boeken kunt ophalen, een boek kunt opvragen op basis van zijn ID, nieuwe boeken kunt toevoegen en zelfs boeken kunt verwijderen. Laten we beginnen.
Inhoudsopgave
Vereisten
Voor we beginnen, zorg ervoor dat je de volgende vereisten op je machine hebt geïnstalleerd:
-
Visual Studio Code of een andere code-editor naar keuze
-
C# Dev Kit voor Visual Studio Code
Als alternatief kunt u Visual Studio 2022 gebruiken, dat ingebouwde ondersteuning biedt voor .NET 8. Maar in dit artikel zullen we Visual Studio Code gebruiken. Het is lichtgewicht, gemakkelijk te gebruiken en cross-platform.
We zullen Swagger UI gebruiken om onze API te testen. Swagger UI is een krachtig hulpmiddel dat u in staat stelt om direct vanuit uw browser met uw API te interageren. Het biedt een gebruiksvriendelijke interface om uw API-eindpunten te testen, waardoor het gemakkelijker wordt om uw API te testen en te debuggen.
Wanneer u een nieuw project maakt, zal het automatisch de benodigde pakketten installeren en het project configureren om Swagger UI te gebruiken. .NET 8 bevat Swagger UI standaard, dus of u nu uw toepassing maakt in Visual Studio of met .NET, Swagger UI zal voor u worden geconfigureerd.
Start uw toepassing, en de Swagger UI zal automatisch openen in uw browser – maar aangezien we VS Code gebruiken, moeten we op het poortnummer in onze terminal klikken.
Je kunt de broncode voor dit project vinden op GitHub.
Inleiding tot Minimal APIs
Stel je voor dat je werkt in een codebase met talloze endpoints, waardoor deze vrij groot en complex is. Traditioneel houdt het bouwen van een API in ASP.NET Core in dat je controllers, routing, middleware en een aanzienlijke hoeveelheid boilerplate-code gebruikt. Maar er zijn twee benaderingen voor het bouwen van een API in ASP.NET Core: de traditionele manier en de minimalistische manier.
De traditionele manier is bekend bij de meeste ontwikkelaars en omvat controllers en uitgebreide infrastructuurcode. De minimalistische manier, geïntroduceerd in .NET 6
, stelt je in staat om APIs te maken met minimale code en geen boilerplate. Deze benadering vereenvoudigt het ontwikkelingsproces, waardoor je je kunt concentreren op het schrijven van bedrijfslogica in plaats van het omgaan met infrastructuurcode.
Minimal APIs zijn lichtgewicht, snel en perfect voor het bouwen van kleine tot middelgrote APIs. Ze zijn ideaal voor prototyping, het bouwen van microservices of het maken van eenvoudige APIs die niet veel complexiteit vereisen. In deze handleiding verkennen we de wereld van minimal APIs in .NET 6 en leren we hoe we een volledig functionele boekwinkel API vanaf nul kunnen maken.
Hoe een Minimal API te maken
Het maken van een minimal API is eenvoudig met behulp van de dotnet CLI
, omdat het standaard sjabloon al een minimal API is. Maar als je Visual Studio gebruikt, moet je de boilerplate-code die bij het project sjabloon wordt geleverd, verwijderen.
Laten we beginnen met het gebruik van de dotnet CLI
om een minimaal API-project te maken.
dotnet new webapi -n BookStoreApi
De opdracht dotnet new webapi
maakt een nieuw minimaal API-project genaamd BookStoreApi
. Dit project bevat de benodigde bestanden en mappen om je op weg te helpen.
Laten we de projectstructuur verkennen:
-
Program.cs
: Het startpunt van de applicatie, waar de host wordt geconfigureerd. -
bookapi-minimal.sln
: Het oplossingsbestand dat het project bevat. -
bookapi-minimal.http
: Een bestand dat voorbeeld-HTTP-verzoeken bevat om de API te testen. -
bookapi-minimal.csproj
: Het projectbestand dat de projectconfiguratie bevat. -
appsettings.json
: Het configuratiebestand dat applicatie-instellingen opslaat. -
appsettings.Development.json
: Het configuratiebestand voor de ontwikkelomgeving.
Wanneer je het program.cs-bestand opent, merk je dat de code minimaal is. Het Program.cs
-bestand bevat de volgende code:
var builder = WebApplication.CreateBuilder(args);
// Voeg services toe aan de container.
// Meer informatie over het configureren van Swagger/OpenAPI op https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configureer de HTTP-verzoekpijplijn.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
var summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
app.MapGet("/weatherforecast", () =>
{
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
))
.ToArray();
return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi();
app.Run();
record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
Als je de code nog niet volledig begrijpt, maak je geen zorgen—we zullen het in detail bespreken in de volgende secties. Het belangrijkste is dat minimale API’s heel weinig code vereisen, wat een van hun belangrijkste voordelen is.
De standaardcode zet een eenvoudige weersvoorspellings-API op die je kunt gebruiken om je setup te testen. Het genereert een lijst van weersvoorspellingen en retourneert deze wanneer je een GET
-verzoek doet naar het /weatherforecast
-eindpunt. Ook bevat de code Swagger UI om je te helpen de API te testen.
Let vooral op de app.MapGet
-methode, die een route toewijst aan een handlerfunctie. In dit geval wijst het de /weatherforecast
-route toe aan een functie die een lijst van weersvoorspellingen retourneert. We zullen soortgelijke methoden gebruiken om onze eigen eindpunten te maken in de volgende secties.
Voordat we beginnen met het maken van onze projectmapstructuur, laten we de HTTP-methoden begrijpen in zowel Controller-based als Minimal API’s.
HTTP-methoden in Controller-based en Minimal API’s
In een Controller-based benadering, wat de traditionele manier is om web API’s te maken, moet je een controllerklasse maken en methoden definiëren voor elke HTTP-methode. Bijvoorbeeld:
-
Om een
GET
methode te creëren, gebruik je de[HttpGet]
attribuut. -
Om een
POST
methode te creëren, gebruik je de[HttpPost]
attribuut. -
Om een
PUT
methode te creëren, gebruik je de[HttpPut]
attribuut. -
Om een
DELETE
methode te creëren, gebruik je de[HttpDelete]
attribuut.
Dit is hoe eindpunten worden gecreëerd in een Controller-gebaseerde benadering.
In tegenstelling hiermee gebruiken Minimal API’s methoden zoals app.MapGet
, app.MapPost
, app.MapPut
, en app.MapDelete
om eindpunten te creëren. Dit is het belangrijkste verschil tussen de twee benaderingen: Controller-gebaseerde API’s gebruiken attributen om eindpunten te definiëren, terwijl Minimal API’s methoden gebruiken.
Nu je begrijpt hoe je HTTP-verzoeken moet afhandelen in zowel Controller-gebaseerde als Minimal API’s, laten we onze projectmapstructuur creëren.
Voordat we onze projectmapstructuur maken, laten we eerst uitvoeren wat we hebben. Zoals we eerder hebben geleerd, wanneer je een project maakt met Visual Studio of .NET CLI, wordt het geleverd met een standaard WeatherForecast-project dat we kunnen uitvoeren en zien op de UI. Laten we het uitvoeren om ervoor te zorgen dat alles werkt voordat we doorgaan met het maken van onze projectmap.
Voer deze opdracht uit:
dotnet run
Je zou de volgende output moeten zien:
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5228
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: D:\Devolopemnt\Dotnet\bookapi-minimal
Dit betekent dat de toepassing draait en luistert op http://localhost:5228
. Zoals ik hierboven al heb vermeld, aangezien we de dotnet CLI
en Visual Studio Code gebruiken, opent de toepassing niet automatisch de browser voor ons. We moeten dit handmatig doen.
Open je browser en navigeer naar http://localhost:5228/swagger/index.html
om de standaardreactie van de API te zien.
Je zou iets dergelijks moeten zien:
Nu is het volgende voor ons om een manier te vinden om onze project te structureren en de nodige bestanden en mappen te maken om te beginnen.
Minimale API-projectbestanden
Om ons project te organiseren, zullen we een gestructureerde maphiërarchie maken. Dit zal helpen om onze code schoon en onderhoudbaar te houden. Hier is de mappenstructuur die we zullen gebruiken:
-
AppContext: Bevat de databasecontext en gerelateerde configuraties.
-
Configuraties: Bevat Entity Framework Core-configuraties en seedgegevens voor de database.
-
Contracten: Bevat Data Transfer Objects (DTO’s) die worden gebruikt in onze toepassing.
-
Eindpunten: Hier definiëren en configureren we onze minimale API-eindpunten.
-
Uitzonderingen: Bevat aangepaste uitzonderingsklassen die worden gebruikt in het project.
-
Extensies: Bevat extensiemethoden die we zullen gebruiken in het project.
-
Modellen: Bevat modellen voor bedrijfslogica.
-
Diensten: Bevat serviceklassen die bedrijfslogica implementeren.
-
Interfaces: Bevat interface-definities die worden gebruikt om onze diensten te mappen.
In Visual Studio Code kun je deze mapstructuur als volgt maken:
- AppContext
- Configurations
- Contracts
- Endpoints
- Exceptions
- Extensions
- Models
- Services
- Interfaces
Na het instellen zou de mapstructuur van je project er als volgt uit moeten zien:
Nu onze projectstructuur is ingesteld, kunnen we doorgaan en onze code gaan schrijven. Laten we beginnen met het maken van onze modellen.
Hoe modellen te maken
In dit gedeelte zullen we modellen maken voor onze applicatie. Modellen zijn de bouwstenen van onze applicatie, die de gegevens vertegenwoordigen waarmee onze applicatie zal werken. Voor ons voorbeeld zullen we een model maken voor een boek.
Om te beginnen, maak een map genaamd Modellen
in je projectdirectory. Maak in deze map een bestand met de naam BookModel.cs
en voeg de volgende code toe:
// Modellen/BookModel.cs
namespace bookapi_minimal.Models
{
public class BookModel
{
public Guid Id { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public string Description { get; set; }
public string Category { get; set; }
public string Language { get; set; }
public int TotalPages { get; set; }
}
}
Deze BookModel-klasse
definieert de eigenschappen die de details van een boek vertegenwoordigen, zoals de titel
, auteur
, beschrijving
, categorie
, taal
en totaal aantal pagina's
. Elke eigenschap is ontworpen om specifieke informatie over het boek vast te houden, waardoor het gemakkelijk is om boekgegevens binnen onze applicatie te beheren en te manipuleren.
Nu we ons model hebben gemaakt, laten we onze databasecontext maken.
Hoe de databasecontext te maken
De databasecontext is een klasse die een sessie met de database vertegenwoordigt. Het is verantwoordelijk voor de interactie met de database en het uitvoeren van databasebewerkingen. In onze applicatie zullen we Entity Framework Core gebruiken om te interageren met onze database.
Installeer de vereiste pakketten
Voor het maken van onze databasecontext moeten we de volgende pakketten installeren:
-
Microsoft.EntityFrameworkCore
-
Microsoft.EntityFrameworkCore.SqlServer
-
FluentValidation.DependencyInjectionExtensions
Je kunt deze pakketten installeren met de volgende commando’s:
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools
dotnet add package FluentValidation.DependencyInjectionExtensions
Controleer Pakketinstallatie
Om te controleren of de pakketten zijn geïnstalleerd, open het bestand bookapi-minimal.csproj
in de hoofdmap van je project. Je zou de geïnstalleerde pakketten als volgt vermeld moeten zien:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>bookapi_minimal</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.9.2" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.8">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
</Project>
Dit bevestigt dat de pakketten succesvol zijn geïnstalleerd.
Nu kunnen we onze databasecontext maken.
In de AppContext-map, maak een nieuw bestand genaamd ApplicationContext.cs
aan en voeg de volgende code toe:
// AppContext/ApplicationContext.cs
using bookapi_minimal.Models;
using Microsoft.EntityFrameworkCore;
namespace bookapi_minimal.AppContext
{
public class ApplicationContext(DbContextOptions<ApplicationContext> options) : DbContext(options)
{
// Standaardschema voor de databasecontext
private const string DefaultSchema = "bookapi";
// DbSet om de verzameling boeken in onze database voor te stellen
public DbSet<BookModel> Books { get; set; }
// Constructor om de databasecontext te configureren
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema(DefaultSchema);
modelBuilder.ApplyConfigurationsFromAssembly(typeof(ApplicationContext).Assembly);
modelBuilder.ApplyConfigurationsFromAssembly(typeof(ApplicationContext).Assembly);
}
}
}
Laten we de bovenstaande code uiteenzetten:
-
We definiëren een klasse genaamd
ApplicationContext
die erft vanDbContext
. De klasseDbContext
maakt deel uit van Entity Framework Core en vertegenwoordigt een sessie met de database. -
De constructor accepteert een instantie van
DbContextOptions<ApplicationContext>
. Deze constructor wordt gebruikt om de databasecontextopties te configureren. -
We definiëren een eigenschap genaamd
Books
van het typeDbSet<BookModel>
. Deze eigenschap vertegenwoordigt de verzameling boeken in onze database. -
We overschrijven de methode
OnModelCreating
om het databaseschema te configureren en eventuele configuraties toe te passen die in onze applicatie zijn gedefinieerd.
Nu we onze database-context hebben aangemaakt, laten we onze extensiemethode maken en onze database-context registreren in de dependency injection-container.
Maak een extensiemethode
Voordat we de extensiemethode maken, laten we begrijpen wat een extensiemethode is in de context van ASP.NET Core.
Een extensiemethode is een statische methode die nieuwe functionaliteit toevoegt aan een bestaand type zonder het oorspronkelijke type te wijzigen. In ASP.NET Core worden extensiemethoden vaak gebruikt om de functionaliteit van de IServiceCollection
-interface uit te breiden, die wordt gebruikt om services te registreren in de dependency injection-container.
Services zijn componenten die functionaliteit bieden aan een applicatie, zoals toegang tot databases, logging en configuratie. Door een extensiemethode te maken voor de IServiceCollection
-interface, kunt u het proces van het registreren van uw services in de dependency injection-container vereenvoudigen.
In plaats van alles in het Program.cs
bestand te plaatsen, zullen we een extensiemethode maken om onze services te registreren in de dependency injection-container. Dit zal ons helpen om onze code schoon en georganiseerd te houden.
In de Extensions
map, maak een nieuw bestand genaamd ServiceExtensions.cs
en voeg de volgende code toe:
using System.Reflection;
using bookapi_minimal.AppContext;
using FluentValidation;
using Microsoft.EntityFrameworkCore;
namespace bookapi_minimal.Extensions
{
public static class ServiceExtensions
{
public static void AddApplicationServices(this IHostApplicationBuilder builder)
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
if (builder.Configuration == null) throw new ArgumentNullException(nameof(builder.Configuration));
// Het toevoegen van de databasecontext
builder.Services.AddDbContext<ApplicationContext>(configure =>
{
configure.UseSqlServer(builder.Configuration.GetConnectionString("sqlConnection"));
});
// Het toevoegen van validators van de huidige assembly
builder.Services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
}
}
}
Laten we de bovenstaande code uitsplitsen:
-
We definiëren een statische klasse genaamd
ServiceExtensions
die een extensiemethode genaamdAddApplicationServices
bevat. Deze methode breidt deIHostApplicationBuilder
interface uit, die wordt gebruikt om de verwerkingspijplijn van het aanvraagverwerking van de applicatie te configureren. -
De
AddApplicationServices
methode accepteert een instantie vanIHostApplicationBuilder
als parameter. Deze parameter wordt gebruikt om toegang te krijgen tot de configuratie en services van de applicatie. -
We voegen de
ApplicationContext
toe aan de dependency injection-container en configureren deze om SQL Server als de databaseprovider te gebruiken. We halen de verbindingsreeks op uit hetappsettings.json
bestand met behulp van deGetConnectionString
methode. -
We voegen
validators
toe van de huidigeassembly
met behulp van deAddValidatorsFromAssembly
methode. Deze methode scant de huidige assembly op klassen die de IValidator-interface implementeren en registreert ze in de dependency injection-container.
Vervolgens moeten we de verbindingsreeks toevoegen aan het appsettings.json
bestand. Voeg de volgende code toe aan je appsettings.json
bestand:
{
"ConnectionStrings": {
"sqlConnection": "Server=localhost\\SQLEXPRESS02;Database=BookAPIMinimalAPI;Integrated Security=true;TrustServerCertificate=true;"
}
}
Zorg ervoor dat je your_password
vervangt door je daadwerkelijke SQL Server wachtwoord.
Je appsettings.json
bestand zou er als volgt uit moeten zien:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
"sqlConnection": "Server=localhost\\SQLEXPRESS02;Database=BookAPIMinimalAPI;Integrated Security=true;TrustServerCertificate=true;"
},
"AllowedHosts": "*"
}
Gefeliciteerd! Je hebt succesvol de databasecontext, extensiemethode en verbindingsreeks voor je applicatie aangemaakt. In de volgende sectie zullen we een Contract aanmaken.
Hoe maak je een contract
Contracten zijn Data Transfer Objects (DTO’s) die de structuur van de gegevens definiëren die worden uitgewisseld tussen de client en de server. In onze applicatie zullen we contracten maken om de gegevens te vertegenwoordigen die worden verzonden en ontvangen door onze API-eindpunten.
Hier zijn de contracten die we gaan maken:
-
CreateBookRequest: Dit vertegenwoordigt de gegevens die worden verzonden bij het maken van een nieuw boek.
-
UpdateBookRequest: Dit vertegenwoordigt de gegevens die worden verzonden bij het bijwerken van een bestaand boek.
-
BookResponse: Vertegenwoordigt de gegevens die worden geretourneerd bij het ophalen van een boek.
-
ErrorResponse: Vertegenwoordigt de foutreactie die wordt geretourneerd wanneer er een uitzondering optreedt.
-
ApiResponse: Vertegenwoordigt de reactie die wordt geretourneerd door de API.
In de map Contracts
, maak een nieuw bestand met de naam CreateBookRequest
en voeg de volgende code toe:
// Contracts/CreateBookRequest.cs
namespace bookapi_minimal.Contracts
{
public record CreateBookRequest
{
public string Title { get; init; }
public string Author { get; init; }
public string Description { get; init; }
public string Category { get; init; }
public string Language { get; init; }
public int TotalPages { get; init; }
}
}
In de map Contracts
, maak een nieuw bestand met de naam UpdateBookRequest
en voeg de volgende code toe:
// Contracten/UpdateBookRequest.cs
namespace bookapi_minimal.Contracts
{
public record UpdateBookRequest
{
public string Title { get; set; }
public string Author { get; set; }
public string Description { get; set; }
public string Category { get; set; }
public string Language { get; set; }
public int TotalPages { get; set; }
}
}
In de Contracten
map, maak een nieuw bestand met de naam BookResponse
en voeg de volgende code toe:
// Contracten/BookResponse.cs
namespace bookapi_minimal.Contracts
{
public record BookResponse
{
public Guid Id { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public string Description { get; set; }
public string Category { get; set; }
public string Language { get; set; }
public int TotalPages { get; set; }
}
}
In de Contracten
map, maak een nieuw bestand met de naam ErrorResponse
en voeg de volgende code toe:
// Contracten/ErrorResponse.cs
namespace bookapi_minimal.Contracts
{
public record ErrorResponse
{
public string Title { get; set; }
public int StatusCode { get; set; }
public string Message { get; set; }
}
}
In de Contracten
map, maak een nieuw bestand met de naam ApiResponse
en voeg de volgende code toe:
// Contracten/ApiResponse.cs
namespace bookapi_minimal.Contracts
{
public class ApiResponse<T>
{
public T Data { get; set; }
public string Message { get; set; }
public ApiResponse(T data, string message)
{
Data = data;
Message = message;
}
}
}
Deze contracten helpen ons bij het definiëren van de structuur van de gegevens die worden uitgewisseld tussen de client en de server, waardoor het gemakkelijker wordt om met de gegevens in onze applicatie te werken.
In het volgende gedeelte zullen we services maken om de bedrijfslogica van onze applicatie te implementeren.
Hoe services toevoegen
Services zijn componenten die functionaliteit bieden aan een applicatie. In onze applicatie zullen we services maken om de bedrijfslogica van onze applicatie te implementeren. We zullen services maken om CRUD-operaties voor boeken af te handelen, boekgegevens te valideren en uitzonderingen af te handelen.
In ASP.NET Core worden services geregistreerd in de dependency injection-container en kunnen ze worden geïnjecteerd in andere componenten, zoals controllers en eindpunten, Maar dit is een minimale API, dus we zullen de services rechtstreeks in de eindpunten injecteren.
Laten we een interface maken voor onze services. In de Interfaces
map, maak een nieuw bestand genaamd IBookService.cs
en voeg de volgende code toe:
// Interfaces/IBookService.cs
using bookapi_minimal.Contracts;
namespace bookapi_minimal.Interfaces
{
public interface IBookService
{
Task<BookResponse> AddBookAsync(CreateBookRequest createBookRequest);
Task<BookResponse> GetBookByIdAsync(Guid id);
Task<IEnumerable<BookResponse>> GetBooksAsync();
Task<BookResponse> UpdateBookAsync(Guid id, UpdateBookRequest updateBookRequest);
Task<bool> DeleteBookAsync(Guid id);
}
}
Laten we de bovenstaande code uitsplitsen: We hebben een interface genaamd IBookService
gedefinieerd die methoden bevat om CRUD-operaties voor boeken te verwerken. De interface definieert de volgende methoden:
-
AddBookAsync
: Voegt een nieuw boek toe aan de database. -
GetBookByIdAsync
: Haalt een boek op aan de hand van zijn ID. -
GetBooksAsync
: Haalt alle boeken op uit de database. -
UpdateBookAsync
: Werkt een bestaand boek bij.
We gebruiken het Contract dat we eerder hebben gemaakt in de Contracts
map. De IBookService
interface definieert de structuur van de methoden die zullen worden geïmplementeerd door de serviceklassen. Dit helpt ons om de interface te scheiden van de implementatie, waardoor het gemakkelijker wordt om onze code te onderhouden en te testen.
Nu we de interface hebben gemaakt, laten we de serviceklasse maken die de interface implementeert.
Hoe de boekenservice te implementeren
Deze service zal de interface IBookService
implementeren en de bedrijfslogica voor onze applicatie bieden. In de map Services
, maak een nieuw bestand genaamd BookService.cs
aan. Je oorspronkelijke bestand zou er als volgt uit moeten zien:
// Services/BookService.cs
namespace bookapi_minimal.Services
{
public class BookService
{
}
}
Het eerste wat we moeten doen is de interface toevoegen aan de klasse BookService
. Werk de klasse BookService
bij om de interface IBookService
te implementeren zoals hieronder:
// Services/BookService.cs
using bookapi_minimal.Interfaces;
namespace bookapi_minimal.Services
{
public class BookService:IBookService
{
}
}
Wanneer je dit doet, kan je VS Code een foutmelding tonen omdat we de methoden in de interface nog niet hebben geïmplementeerd. Laten we doorgaan en de methoden in de klasse BookService
implementeren.
In VS Code kan je de sneltoets Ctrl + .
gebruiken om de methoden in de interface te implementeren. Dan zal je de volgende code gegenereerd zien worden:
using bookapi_minimal.Contracts;
using bookapi_minimal.Interfaces;
namespace bookapi_minimal.Services
{
// Serviceklasse voor het beheren van boeken
public class BookService : IBookService
{
// Methode om een nieuw boek aan de database toe te voegen
public Task<BookResponse> AddBookAsync(CreateBookRequest createBookRequest)
{
throw new NotImplementedException();
}
// Methode om een boek uit de database te verwijderen
public Task<bool> DeleteBookAsync(Guid id)
{
throw new NotImplementedException();
}
// Methode om een boek uit de database op te halen aan de hand van zijn ID
public Task<BookResponse> GetBookByIdAsync(Guid id)
{
throw new NotImplementedException();
}
// Methode om alle boeken uit de database op te halen
public Task<IEnumerable<BookResponse>> GetBooksAsync()
{
throw new NotImplementedException();
}
// Methode om een boek in de database bij te werken
public Task<BookResponse> UpdateBookAsync(Guid id, UpdateBookRequest updateBookRequest)
{
throw new NotImplementedException();
}
}
}
Nu kunt u zien dat de methoden in de interface zijn geïmplementeerd in de klasse BookService
. We zullen de bedrijfslogica implementeren voor elke methode in de volgende sectie.
Voordat we dat doen, laten we de benodigde afhankelijkheden toevoegen aan de klasse BookService
. We moeten de afhankelijkheden ApplicationContext
en ILogger
injecteren in de klasse BookService
. ApplicationContext
wordt gebruikt om te communiceren met de database, terwijl ILogger
wordt gebruikt voor logging.
Om de afhankelijkheden te injecteren, werk de klasse BookService
als volgt bij:
// Services/BookService.cs
// ...
private readonly ApplicationContext _context; // Database context
private readonly ILogger<BookService> _logger; // Logger voor het vastleggen van informatie en fouten
//..
Aangezien we de afhankelijkheden hebben toegevoegd, moeten we de constructor van BookService
bijwerken om de afhankelijkheden te accepteren. Werk de constructor van BookService
als volgt bij:
// Services/BookService.cs
// ...
// Constructor om de databasecontext en logger te initialiseren
public BookService(ApplicationContext context, ILogger<BookService> logger)
{
_context = context;
_logger = logger;
}
// ...
Nu we de afhankelijkheden hebben toegevoegd en de constructor hebben bijgewerkt, kunnen we de bedrijfslogica implementeren voor elke methode in de klasse BookService
.
Laten we logica creëren voor de CREATE, READ, UPDATE en DELETE operaties in de BookService
klasse.
Hoe de AddBookAsync
Methode Implementeren
Zoals eerder vermeld, zullen we de AddBookAsync
methode gebruiken om een nieuw boek aan de database toe te voegen. In deze methode zullen we een nieuwe boek entiteit maken, de gegevens van het CreateBookRequest
object naar de boek entiteit mappen en de boek entiteit opslaan in de database. We zullen ook de boek entiteit retourneren als een BookResponse
object.
Update de AddBookAsync
methode in de BookService
klasse als volgt:
// Services/BookService.cs
// ...
/// <summary>
/// Voeg een nieuw boek toe
/// </summary>
/// <param name="createBookRequest">Boekverzoek dat moet worden toegevoegd</param>
/// <returns>Details van het aangemaakte boek</returns>
public async Task<BookResponse> AddBookAsync(CreateBookRequest createBookRequest)
{
try
{
var book = new BookModel
{
Title = createBookRequest.Title,
Author = createBookRequest.Author,
Description = createBookRequest.Description,
Category = createBookRequest.Category,
Language = createBookRequest.Language,
TotalPages = createBookRequest.TotalPages
};
// Voeg het boek toe aan de database
_context.Books.Add(book);
await _context.SaveChangesAsync();
_logger.LogInformation("Book added successfully.");
// Retourneer de details van het aangemaakte boek
return new BookResponse
{
Id = book.Id,
Title = book.Title,
Author = book.Author,
Description = book.Description,
Category = book.Category,
Language = book.Language,
TotalPages = book.TotalPages
};
}
catch (Exception ex)
{
_logger.LogError($"Error adding book: {ex.Message}");
throw;
}
}
// ...
In deze code maken we een nieuwe boek entiteit aan vanuit het CreateBookRequest
object, mappen we de data van het CreateBookRequest
object naar de boek entiteit, slaan we de boek entiteit op in de database, en retourneren we de boek entiteit als een BookResponse
object.
We loggen ook informatie en fouten met behulp van de ILogger
afhankelijkheid. Als er een uitzondering optreedt tijdens het proces, loggen we het foutbericht en gooien we de uitzondering opnieuw.
Nu we de AddBookAsync
methode geïmplementeerd hebben, laten we de GetBookByIdAsync
methode implementeren.
Hoe de GetBookByIdAsync
Methode te Implementeren
De GetBookByIdAsync
methode wordt gebruikt om een boek op te halen aan de hand van zijn ID uit de database. In deze methode zullen we de database bevragen voor het boek met het gespecificeerde ID, de boek entiteit mappen naar een BookResponse
object, en het BookResponse
object retourneren.
Update de GetBookByIdAsync
methode in de BookService
klasse als volgt:
// Services/BookService.cs
//...
/// <summary>
/// Haal een boek op aan de hand van zijn ID
/// </summary>
/// <param name="id">ID van het boek</param>
/// <returns>Details van het boek</returns>
public async Task<BookResponse> GetBookByIdAsync(Guid id)
{
try
{
// Vind het boek aan de hand van zijn ID
var book = await _context.Books.FindAsync(id);
if (book == null)
{
_logger.LogWarning($"Book with ID {id} not found.");
return null;
}
// Geef de details van het boek terug
return new BookResponse
{
Id = book.Id,
Title = book.Title,
Author = book.Author,
Description = book.Description,
Category = book.Category,
Language = book.Language,
TotalPages = book.TotalPages
};
}
catch (Exception ex)
{
_logger.LogError($"Error retrieving book: {ex.Message}");
throw;
}
}
//...
In deze code bevragen we de database naar het boek met het opgegeven ID, mappen de boekentiteit naar een BookResponse
object, en retourneren het BookResponse
object. We loggen ook informatie en fouten met behulp van de ILogger
afhankelijkheid.
Als het boek met het opgegeven ID niet wordt gevonden, loggen we een waarschuwingsbericht en retourneren null. Als er een uitzondering optreedt tijdens het proces, loggen we het foutenbericht en gooien we de uitzondering opnieuw.
Nu we de GetBookByIdAsync
methode hebben geïmplementeerd, laten we de GetBooksAsync
methode implementeren.
Hoe de GetBooksAsync
Methode te Implementeren
De methode GetBooksAsync
wordt gebruikt om alle boeken uit de database op te halen. In deze methode zullen we de database bevragen voor alle boeken, elke boekentiteit toewijzen aan een BookResponse
-object, en een lijst van BookResponse
-objecten retourneren.
Update de methode GetBooksAsync
in de klasse BookService
als volgt:
// Services/BookService.cs
//...
/// <summary>
/// Alle boeken ophalen
/// </summary>
/// <returns>Lijst van alle boeken</returns>
public async Task<IEnumerable<BookResponse>> GetBooksAsync()
{
try
{
// Alle boeken uit de database ophalen
var books = await _context.Books.ToListAsync();
// De details van alle boeken retourneren
return books.Select(book => new BookResponse
{
Id = book.Id,
Title = book.Title,
Author = book.Author,
Description = book.Description,
Category = book.Category,
Language = book.Language,
TotalPages = book.TotalPages
});
}
catch (Exception ex)
{
_logger.LogError($"Error retrieving books: {ex.Message}");
throw;
}
}
//...
Hier bevragen we de database voor alle boeken, elke boekentiteit toewijzen aan een BookResponse
-object, en een lijst van BookResponse
-objecten retourneren. We loggen ook informatie en fouten met behulp van de ILogger
-afhankelijkheid. Als er een uitzondering optreedt tijdens het proces, loggen we het foutbericht en gooien we de uitzondering opnieuw.
Nu we de methode GetBooksAsync
hebben geïmplementeerd, laten we de methode UpdateBookAsync
implementeren.
Hoe de methode UpdateBookAsync
te implementeren
De methode UpdateBookAsync
wordt gebruikt om een bestaand boek in de database bij te werken. In deze methode zullen we de database bevragen voor het boek met de gespecificeerde ID, het boekentiteit bijwerken met de gegevens uit het UpdateBookRequest
-object, de bijgewerkte boekentiteit opslaan in de database, en de bijgewerkte boekentiteit teruggeven als een BookResponse
-object.
Update de UpdateBookAsync
-methode in de BookService
-klasse als volgt:
// Services/BookService.cs
//...
/// <summary>
/// Werk een bestaand boek bij
/// </summary>
/// <param name="id">ID van het te bijwerken boek</param>
/// <param name="book">Bijgewerkt boekmodel</param>
/// <returns>Details van het bijgewerkte boek</returns>
public async Task<BookResponse> UpdateBookAsync(Guid id, UpdateBookRequest book)
{
try
{
// Vind het bestaande boek op basis van de ID
var existingBook = await _context.Books.FindAsync(id);
if (existingBook == null)
{
_logger.LogWarning($"Book with ID {id} not found.");
return null;
}
// Werk de boekgegevens bij
existingBook.Title = book.Title;
existingBook.Author = book.Author;
existingBook.Description = book.Description;
existingBook.Category = book.Category;
existingBook.Language = book.Language;
existingBook.TotalPages = book.TotalPages;
// Sla de wijzigingen op in de database
await _context.SaveChangesAsync();
_logger.LogInformation("Book updated successfully.");
// Geef de details van het bijgewerkte boek terug
return new BookResponse
{
Id = existingBook.Id,
Title = existingBook.Title,
Author = existingBook.Author,
Description = existingBook.Description,
Category = existingBook.Category,
Language = existingBook.Language,
TotalPages = existingBook.TotalPages
};
}
catch (Exception ex)
{
_logger.LogError($"Error updating book: {ex.Message}");
throw;
}
}
//...
Hier worden we de database bevragen voor het boek met het gespecificeerde ID, wordt de boekentiteit bijgewerkt met de gegevens uit het UpdateBookRequest
-object, de bijgewerkte boekentiteit wordt opgeslagen in de database en geretourneerd als een BookResponse
-object. We loggen ook informatie en fouten met behulp van de ILogger
-afhankelijkheid.
Als het boek met het gespecificeerde ID niet wordt gevonden, loggen we een waarschuwingsbericht en retourneren null. Als er een uitzondering optreedt tijdens het proces, loggen we het foutbericht en gooi de uitzondering opnieuw.
Nu we de methode UpdateBookAsync
hebben geïmplementeerd, laten we de methode DeleteBookAsync
implementeren.
Hoe de methode DeleteBookAsync
te implementeren
De methode DeleteBookAsync
wordt gebruikt om een bestaand boek uit de database te verwijderen. In deze methode bevragen we de database voor het boek met het gespecificeerde ID, verwijderen de boekentiteit uit de database en retourneren een boolean-waarde die aangeeft of het boek succesvol is verwijderd.
Update de methode DeleteBookAsync
in de klasse BookService
als volgt:
// Services/BookService.cs
//...
/// <summary>
/// Verwijder een boek op basis van het ID
/// </summary>
/// <param name="id">ID van het te verwijderen boek</param>
/// <returns>True als het boek is verwijderd, anders false</returns>
public async Task<bool> DeleteBookAsync(Guid id)
{
try
{
// Vind het boek op basis van het ID
var book = await _context.Books.FindAsync(id);
if (book == null)
{
_logger.LogWarning($"Book with ID {id} not found.");
return false;
}
// Verwijder het boek uit de database
_context.Books.Remove(book);
await _context.SaveChangesAsync();
_logger.LogInformation($"Book with ID {id} deleted successfully.");
return true;
}
catch (Exception ex)
{
_logger.LogError($"Error deleting book: {ex.Message}");
throw;
}
}
//...
In deze code bevragen we de database voor het boek met het opgegeven ID, verwijderen we de boekentiteit uit de database, en geven we een booleaanse waarde terug die aangeeft of het boek succesvol is verwijderd. We loggen ook informatie en fouten met behulp van de ILogger
afhankelijkheid.
Als het boek met het opgegeven ID niet wordt gevonden, loggen we een waarschuwingsbericht en geven we false terug. Als er een uitzondering optreedt tijdens het proces, loggen we het foutbericht en gooien we de uitzondering opnieuw.
Nu heb je succesvol de bedrijfslogica geïmplementeerd voor de AddBookAsync
, GetBookByIdAsync
, GetBooksAsync
, UpdateBookAsync
en DeleteBookAsync
methoden in de BookService
klasse. Deze methoden behandelen de CRUD-operaties voor boeken, valideren boekgegevens en behandelen uitzonderingen. Op dit moment zou je BookService
klasse er ongeveer zo uit moeten zien:
using bookapi_minimal.AppContext;
using bookapi_minimal.Contracts;
using bookapi_minimal.Interfaces;
using bookapi_minimal.Models;
using Microsoft.EntityFrameworkCore;
namespace bookapi_minimal.Services
{
public class BookService : IBookService
{
private readonly ApplicationContext _context; // Databasecontext
private readonly ILogger<BookService> _logger; // Logger voor het loggen van informatie en fouten
// Constructor om de databasecontext en logger te initialiseren
public BookService(ApplicationContext context, ILogger<BookService> logger)
{
_context = context;
_logger = logger;
}
/// Voeg een nieuw boek toe
/// </samenvatting>
/// <param name="createBookRequest">Boekverzoek dat moet worden toegevoegd</param>
/// <returns>Details van het aangemaakte boek</returns>
public async Task<BookResponse> AddBookAsync(CreateBookRequest createBookRequest)
{
try
{
var book = new BookModel
{
Title = createBookRequest.Title,
Author = createBookRequest.Author,
Description = createBookRequest.Description,
Category = createBookRequest.Category,
Language = createBookRequest.Language,
TotalPages = createBookRequest.TotalPages
};
// Voeg het boek toe aan de database
_context.Books.Add(book);
await _context.SaveChangesAsync();
_logger.LogInformation("Book added successfully.");
// Geef de details van het aangemaakte boek terug
return new BookResponse
{
Id = book.Id,
Title = book.Title,
Author = book.Author,
Description = book.Description,
Category = book.Category,
Language = book.Language,
TotalPages = book.TotalPages
};
}
catch (Exception ex)
{
_logger.LogError($"Error adding book: {ex.Message}");
throw;
}
}
/// <samenvatting>
/// Haal een boek op aan de hand van zijn ID
/// </samenvatting>
/// <param name="id">ID van het boek</param>
/// <returns>Details van het boek</returns>
public async Task<BookResponse> GetBookByIdAsync(Guid id)
{
try
{
// Vind het boek op basis van zijn ID
var book = await _context.Books.FindAsync(id);
if (book == null)
{
_logger.LogWarning($"Book with ID {id} not found.");
return null;
}
// Geef de details van het boek terug
return new BookResponse
{
Id = book.Id,
Title = book.Title,
Author = book.Author,
Description = book.Description,
Category = book.Category,
Language = book.Language,
TotalPages = book.TotalPages
};
}
catch (Exception ex)
{
_logger.LogError($"Error retrieving book: {ex.Message}");
throw;
}
}
/// <samenvatting>
/// Haal alle boeken op
/// </samenvatting>
/// <returns>Lijst van alle boeken</returns>
public async Task<IEnumerable<BookResponse>> GetBooksAsync()
{
try
{
// Haal alle boeken op uit de database
var books = await _context.Books.ToListAsync();
// Geef de details van alle boeken terug
return books.Select(book => new BookResponse
{
Id = book.Id,
Title = book.Title,
Author = book.Author,
Description = book.Description,
Category = book.Category,
Language = book.Language,
TotalPages = book.TotalPages
});
}
catch (Exception ex)
{
_logger.LogError($"Error retrieving books: {ex.Message}");
throw;
}
}
/// <samenvatting>
/// Werk een bestaand boek bij
/// </samenvatting>
/// <param name="id">ID van het te updaten boek</param>
/// <param name="book">Bijgewerkt boekmodel</param>
/// <returns>Details van het bijgewerkte boek</returns>
public async Task<BookResponse> UpdateBookAsync(Guid id, UpdateBookRequest book)
{
try
{
// Vind het bestaande boek op basis van zijn ID
var existingBook = await _context.Books.FindAsync(id);
if (existingBook == null)
{
_logger.LogWarning($"Book with ID {id} not found.");
return null;
}
// Werk de boekdetails bij
existingBook.Title = book.Title;
existingBook.Author = book.Author;
existingBook.Description = book.Description;
existingBook.Category = book.Category;
existingBook.Language = book.Language;
existingBook.TotalPages = book.TotalPages;
// Sla de wijzigingen op in de database
await _context.SaveChangesAsync();
_logger.LogInformation("Book updated successfully.");
// Geef de details van het bijgewerkte boek terug
return new BookResponse
{
Id = existingBook.Id,
Title = existingBook.Title,
Author = existingBook.Author,
Description = existingBook.Description,
Category = existingBook.Category,
Language = existingBook.Language,
TotalPages = existingBook.TotalPages
};
}
catch (Exception ex)
{
_logger.LogError($"Error updating book: {ex.Message}");
throw;
}
}
/// <samenvatting>
/// Verwijder een boek aan de hand van zijn ID
/// </samenvatting>
/// <param name="id">ID van het te verwijderen boek</param>
/// <returns>True als het boek is verwijderd, anders false</returns>
public async Task<bool> DeleteBookAsync(Guid id)
{
try
{
// Vind het boek op basis van zijn ID
var book = await _context.Books.FindAsync(id);
if (book == null)
{
_logger.LogWarning($"Book with ID {id} not found.");
return false;
}
// Verwijder het boek uit de database
_context.Books.Remove(book);
await _context.SaveChangesAsync();
_logger.LogInformation($"Book with ID {id} deleted successfully.");
return true;
}
catch (Exception ex)
{
_logger.LogError($"Error deleting book: {ex.Message}");
throw;
}
}
}
}
Gefeliciteerd! U heeft succesvol de bedrijfslogica geïmplementeerd voor de methoden AddBookAsync
, GetBookByIdAsync
, GetBooksAsync
, UpdateBookAsync
en DeleteBookAsync
in de klasse BookService
.
Er is nog één ding dat we moeten doen: we moeten de service registreren in onze extensiemethode. Laten we dat nu doen.
Voeg in uw bestand ServiceExtensions.cs
de volgende code toe:
// Extensions/ServiceExtensions.cs
//..
builder.Services.AddScoped<IBookService, BookService>();
//...
Dit zal de klasse BookService
registreren als een scoped service. Dit betekent dat de service één keer per verzoek wordt aangemaakt en na het voltooien van het verzoek wordt verwijderd.
Nu de service werkt, laten we doorgaan en de uitzonderingsklassen maken.
Hoe uitzonderingen te maken
Het correct omgaan met uitzonderingen is cruciaal om de stabiliteit en betrouwbaarheid van een applicatie te waarborgen. In de context van ASP.NET Core zijn er twee hoofdtypen uitzonderingen:
-
Systeemuitzonderingen: Dit zijn uitzonderingen die worden gegenereerd door de .NET-runtime of het onderliggende systeem.
-
Toepassingsuitzonderingen: Dit zijn uitzonderingen die worden gegenereerd door de toepassingscode om specifieke fouten of omstandigheden af te handelen.
In ASP.NET Core met .NET 8 is een nieuwe functie geïntroduceerd genaamd globale uitzonderingsafhandeling. Deze functie stelt u in staat om uitzonderingen op globaal niveau in uw toepassing te beheren, waardoor het gemakkelijker wordt om fouten te beheren en een consistente gebruikerservaring te bieden.
In onze toepassing zullen we aangepaste uitzonderingsklassen maken om specifieke fouten en situaties te behandelen. We zullen ook gebruikmaken van de functie voor globale uitzonderingsafhandeling om uitzonderingen op globaal niveau te beheren, ervoor zorgend dat er een uniforme benadering van foutafhandeling wordt toegepast in de gehele toepassing.
We gaan de volgende uitzonderingsklassen maken:
-
NoBookFoundException
: Gegenereerd wanneer een boek met de gespecificeerde ID niet wordt gevonden. -
BookDoesNotExistException
: Gegenereerd wanneer een boek met de gespecificeerde ID niet bestaat. -
GlobalExceptionHandler
: Behandelt uitzonderingen op globaal niveau in de toepassing.
In de map Uitzonderingen
maak een nieuw bestand met de naam NoBookFoundException.cs
en voeg de volgende code toe:
// Uitzonderingen/NoBookFoundException.cs
namespace bookapi_minimal.Exceptions
{
public class NoBookFoundException : Exception
{
public NoBookFoundException() : base("No books found")
{}
}
}
In deze code creëren we een aangepaste uitzonderingsklasse met de naam NoBookFoundException
die overerft van de klasse Exception
. De klasse NoBookFoundException
wordt gebruikt om het scenario te behandelen waarin er geen boeken worden gevonden in de database. We voorzien ook een aangepast foutbericht voor de uitzondering.
In de map Exceptions
maak een nieuw bestand met de naam BookDoesNotExistException.cs
en voeg de volgende code toe:
namespace bookapi_minimal.Exceptions
{
public class BookDoesNotExistException : Exception
{
private int id { get; set; }
public BookDoesNotExistException(int id) : base($"Book with id {id} does not exist")
{
this.id = id;
}
}
}
In deze code creëren we een aangepaste uitzonderingsklasse met de naam BookDoesNotExistException
die overerft van de klasse Exception
. De klasse BookDoesNotExistException
wordt gebruikt om het scenario te behandelen waarin een boek met de gespecificeerde ID niet bestaat in de database. We voorzien ook een aangepast foutbericht voor de uitzondering.
In de map Exceptions
maak een nieuw bestand met de naam GlobalExceptionHandler.cs
en voeg de volgende code toe:
// Uitzonderingen/GlobalExceptionHandler.cs
using System.Net;
using bookapi_minimal.Contracts;
using Microsoft.AspNetCore.Diagnostics;
namespace bookapi_minimal.Exceptions
{
// Globale uitzondering handler klasse die IExceptionHandler implementeert
public class GlobalExceptionHandler : IExceptionHandler
{
private readonly ILogger<GlobalExceptionHandler> _logger;
// Constructor om de logger te initialiseren
public GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger)
{
_logger = logger;
}
// Methode om uitzonderingen asynchroon af te handelen
public async ValueTask<bool> TryHandleAsync(
HttpContext httpContext,
Exception exception,
CancellationToken cancellationToken)
{
// Log de details van de uitzondering
_logger.LogError(exception, "An error occurred while processing your request");
var errorResponse = new ErrorResponse
{
Message = exception.Message,
Title = exception.GetType().Name
};
// Bepaal de statuscode op basis van het type uitzondering
switch (exception)
{
case BadHttpRequestException:
errorResponse.StatusCode = (int)HttpStatusCode.BadRequest;
break;
case NoBookFoundException:
case BookDoesNotExistException:
errorResponse.StatusCode = (int)HttpStatusCode.NotFound;
break;
default:
errorResponse.StatusCode = (int)HttpStatusCode.InternalServerError;
break;
}
// Stel de statuscode van de reactie in
httpContext.Response.StatusCode = errorResponse.StatusCode;
// Schrijf de foutreactie als JSON
await httpContext.Response.WriteAsJsonAsync(errorResponse, cancellationToken);
// Geef true terug om aan te geven dat de uitzondering is afgehandeld
return true;
}
}
}
Laten we de bovenstaande code ontleden:
-
We definiëren een klasse genaamd
GlobalExceptionHandler
die deIExceptionHandler
interface implementeert. DeIExceptionHandler
interface wordt gebruikt om uitzonderingen globaal in de applicatie af te handelen. -
De
GlobalExceptionHandler
klasse bevat een constructor die deILogger<GlobalExceptionHandler>
afhankelijkheid initialiseerd. DeILogger
wordt gebruikt voor het loggen van informatie en fouten. -
De methode
TryHandleAsync
wordt gebruikt om uitzonderingen asynchroon af te handelen. Deze methode accepteert deHttpContext
,Exception
enCancellationToken
als parameters. -
We loggen de uitzonderingsdetails met behulp van de
ILogger
afhankelijkheid. -
We maken een
ErrorResponse
object aan om de foutmelding te vertegenwoordigen die door de API wordt geretourneerd. HetErrorResponse
object bevat de foutmelding, titel en statuscode. -
We bepalen de statuscode op basis van het type uitzondering. Als de uitzondering een
BadHttpRequestException
is, stellen we de statuscode in opBadRequest
. Als de uitzondering eenNoBookFoundException
ofBookDoesNotExistException
is, stellen we de statuscode in opNotFound
. Anders stellen we de statuscode in opInternalServerError
. -
We stellen de statuscode van de respons in met behulp van de eigenschap
httpContext.Response.StatusCode
. -
We schrijven de foutrespons als JSON met behulp van de methode
httpContext.Response.WriteAsJsonAsync
. -
We geven
true
terug om aan te geven dat de uitzondering succesvol is afgehandeld.
Nu we de uitzonderingsklassen hebben aangemaakt, laten we de GlobalExceptionHandler
registreren in de dependency injection-container. Aangezien we een Extensiemethode hebben gemaakt voor het registreren van services in de dependency injection-container, voegen we de GlobalExceptionHandler
toe aan de klasse ServiceExtensions
.
Update de klasse ServiceExtensions
in de map Extensions
als volgt:
// Extensies/ServiceExtensies.cs
//...
builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
builder.Services.AddProblemDetails();
//...
De methode AddExceptionHandler
registreert de GlobalExceptionHandler
in de dependency injection-container. De methode AddProblemDetails
registreert de klasse ProblemDetails
in de dependency injection-container.
Nu we de GlobalExceptionHandler
hebben geregistreerd in de dependency injection-container, kunnen we deze gebruiken om uitzonderingen globaal af te handelen in onze applicatie. In de volgende sectie zullen we de API-eindpunten maken om te communiceren met de boekgegevens.
Hoe u de API-eindpunten kunt maken
In de context van minimale API’s in ASP.NET Core zijn er veel manieren om uw eindpunten in te stellen.
U kunt ze rechtstreeks definiëren in uw bestand Program.cs
. Maar naarmate uw project groeit en u meer eindpunten of functionaliteit moet toevoegen, is het handig om uw code beter te organiseren. Een manier om dit te bereiken is door een aparte klasse te maken om alle eindpunten af te handelen.
Zoals hierboven besproken, gebruiken minimale API’s geen controllers of views zoals traditionele ASP.NET Core-toepassingen. In plaats daarvan gebruiken ze methoden zoals MapGet
, MapPost
, MapPut
en MapDelete
om HTTP-methoden en routes voor API-eindpunten te definiëren.
Om te beginnen, navigeer naar de map Eindpunten
en maak een nieuw bestand met de naam BookEindpunten.cs
. Voeg de volgende code toe aan het bestand:
// Eindpunten/BookEndpoints.cs
namespace bookapi_minimal.Endpoints
{
public static class BookEndPoint
{
public static IEndpointRouteBuilder MapBookEndPoint(this IEndpointRouteBuilder app)
{
return app;
}
}
}
De klasse BookEndpoints
bevat een methode MapBookEndPoint
die een object van het type IEndpointRouteBuilder
retourneert. Het IEndpointRouteBuilder
-object wordt gebruikt om de HTTP-methoden en routes voor de API-eindpunten te definiëren. In de volgende secties zullen we de API-eindpunten definiëren voor het creëren
, lezen
, bijwerken
en verwijderen
van boeken.
Hoe maak je het eindpunt AddBookAsync
Books
In deze sectie zullen we het eindpunt AddBookAsync
creëren. Dit eindpunt zal een object van het type Book
accepteren als JSON-payload en het toevoegen aan de database. We zullen de methode MapPost
gebruiken om de HTTP-methode en route voor dit eindpunt te definiëren.
Voeg de volgende code toe aan de klasse BookEndpoints
:
// Eindpunten/BookEndpoints.cs
//...
// Eindpunt om een nieuw boek toe te voegen
app.MapPost("/books", async (CreateBookRequest createBookRequest, IBookService bookService) =>
{
var result = await bookService.AddBookAsync(createBookRequest);
return Results.Created($"/books/{result.Id}", result);
});
//...
-
Routedefinitie: De MapPost-methode definieert de route voor het eindpunt als
/boeken
. -
Aanvraagmodel: Het eindpunt accepteert een object van het type
CreateBookRequest
als JSON-payload. Het objectCreateBookRequest
bevat de gegevens die nodig zijn om een nieuw boek te creëren. -
Reactiemodel: Het eindpunt retourneert een
Book
-object als JSON-payload. HetBook
-object bevat de gegevens voor het nieuw aangemaakte boek. -
Teruggegeven waarde: Het eindpunt retourneert een
Created
-resultaat. HetCreated
-resultaat bevat de locatie van het nieuw aangemaakte boek en hetBook
-object.
Hoe de GetBookAsync
Boek Eindpunt te Creëren
In dit gedeelte zullen we het GetBookAsync
-eindpunt creëren. Dit eindpunt zal een boek-ID accepteren als een queryparameter en het boek met de gespecificeerde ID retourneren. We zullen de MapGet
-methode gebruiken om de HTTP-methode en route voor dit eindpunt te definiëren.
Voeg de volgende code toe aan de klasse BookEndpoints
:
// Eindpunten/BookEindpunten.cs
// ...
// Eindpunt om alle boeken op te halen
app.MapGet("/books", async (IBookService bookService) =>
{
var result = await bookService.GetBooksAsync();
return Results.Ok(result);
});
//...
-
Route Definitie: De MapGet methode definieert de route voor het eindpunt als
/boeken
. -
Verzoek Model: Het eindpunt accepteert een
Boek
object als een JSON-payload. HetBoek
object bevat de gegevens die nodig zijn om een nieuw boek te maken. -
Antwoord Model: Het eindpunt geeft een
Boek
object terug als een JSON-payload. HetBoek
object bevat de gegevens voor het nieuw gemaakte boek. -
Teruggegeven Waarde: Het eindpunt geeft een
Ok
resultaat terug. HetOk
resultaat bevat hetBoek
object.
Hoe de GetBoekByIdAsync
Boek Eindpunt te maken
In deze sectie zullen we het GetBookByIdAsync
eindpunt creëren. Dit eindpunt zal een boek-ID accepteren als een route parameter en het boek met het gespecificeerde ID retourneren. We zullen de MapGet
methode gebruiken om de HTTP-methode en route voor dit eindpunt te definiëren.
Voeg de volgende code toe aan de BookEndpoints
klasse:
// Eindpunten/BookEndpoints.cs
//...
// Eindpunt om een boek op te halen op basis van ID
app.MapGet("/books/{id:guid}", async (Guid id, IBookService bookService) =>
{
var result = await bookService.GetBookByIdAsync(id);
return result != null ? Results.Ok(result) : Results.NotFound();
});
//...
-
Routedefinitie: De MapGet methode definieert de route voor het eindpunt als
/boeken/{id:guid}
. De{id:guid}
parameter specificeert dat deid
parameter een GUID moet zijn. -
Aanvraagmodel: Het eindpunt accepteert een
Boek
object als een JSON-payload. HetBoek
object bevat de gegevens die nodig zijn om een nieuw boek te maken. -
Reactiemodel: Het eindpunt retourneert een
Boek
object als een JSON-payload. HetBoek
object bevat de gegevens voor het nieuw gecreëerde boek. -
Retourwaarde: Het eindpunt retourneert een
Ok
-resultaat als het boek wordt gevonden. Het resultaatNiet gevonden
wordt geretourneerd als het boek niet wordt gevonden.
Hoe u het eindpunt UpdateBookAsync
Boek kunt aanmaken
In dit gedeelte zullen we het eindpunt UpdateBookAsync
aanmaken. Dit eindpunt zal een boek-ID accepteren als een routeparameter en een Boek
-object als JSON-payload en het boek met de gespecificeerde ID bijwerken. We zullen de methode MapPut
gebruiken om de HTTP-methode en route voor dit eindpunt te definiëren.
Voeg de volgende code toe aan de klasse BookEndpoints
:
// Eindpunten/BookEndpoints.cs
//...
// Eindpunt om een boek bij te werken op basis van ID
app.MapPut("/books/{id:guid}", async (Guid id, UpdateBookRequest updateBookRequest, IBookService bookService) =>
{
var result = await bookService.UpdateBookAsync(id, updateBookRequest);
return result != null ? Results.Ok(result) : Results.NotFound();
});
//...
-
Routedefinitie: De MapPut-methode definieert de route voor het eindpunt als
/boeken/{id:guid}
. De parameter{id:guid}
specificeert dat de parameterid
een GUID moet zijn. -
Aanvraagmodel: Het eindpunt accepteert een
Book
-object als JSON-payload. HetBook
-object bevat de gegevens die nodig zijn om een nieuw boek te maken. -
Reactiemodel: Het eindpunt retourneert een
Book
-object als JSON-payload. HetBook
-object bevat de gegevens voor het nieuw aangemaakte boek. -
Teruggegeven Waarde: Het eindpunt retourneert een
Ok
-resultaat als het boek gevonden is. Het resultaatNotFound
wordt geretourneerd als het boek niet gevonden is.
Hoe de DeleteBookAsync
-boek Eindpunt te Creëren
In deze sectie zullen we het DeleteBookAsync
eindpunt creëren. Dit eindpunt zal een boek-ID accepteren als een route parameter en het boek met het gespecificeerde ID verwijderen. We zullen de MapDelete
methode gebruiken om de HTTP-methode en route voor dit eindpunt te definiëren.
Voeg de volgende code toe aan de BookEndpoints
klasse:
// Eindpunten/BookEndpoints.cs
//...
// Eindpunt om een boek te verwijderen op basis van ID
app.MapDelete("/books/{id:guid}", async (Guid id, IBookService bookService) =>
{
var result = await bookService.DeleteBookAsync(id);
return result ? Results.NoContent() : Results.NotFound();
});
//...
-
Routedefinitie: De MapDelete methode definieert de route voor het eindpunt als
/boeken/{id:guid}
. De{id:guid}
parameter specificeert dat deid
parameter een GUID moet zijn. -
Verzoekmodel: Het eindpunt accepteert een
Boek
object als een JSON-payload. HetBoek
object bevat de gegevens die nodig zijn om een nieuw boek te creëren. - Reactiemodel: Het eindpunt retourneert een
Boek
object als een JSON-payload. HetBoek
object bevat de gegevens voor het nieuw gecreëerde boek. -
Retourwaarde: Het eindpunt retourneert een
GeenInhoud
-resultaat als het boek succesvol is verwijderd. HetNietGevonden
-resultaat wordt geretourneerd als het boek niet gevonden is.
Nu hebben we alle methoden voor de boekeindpunten gedefinieerd. Dus uw eindpuntenklasse zou er als volgt uit moeten zien:
// Eindpunten/BoekEindpunten.cs
using bookapi_minimal.Contracts;
using bookapi_minimal.Interfaces;
namespace bookapi_minimal.Endpoints
{
public static class BookEndPoint
{
public static IEndpointRouteBuilder MapBookEndPoint(this IEndpointRouteBuilder app)
{
// Definieer de eindpunten
// Eindpunt om een nieuw boek toe te voegen
app.MapPost("/books", async (CreateBookRequest createBookRequest, IBookService bookService) =>
{
var result = await bookService.AddBookAsync(createBookRequest);
return Results.Created($"/books/{result.Id}", result);
});
// Eindpunt om alle boeken op te halen
app.MapGet("/books", async (IBookService bookService) =>
{
var result = await bookService.GetBooksAsync();
return Results.Ok(result);
});
// Eindpunt om een boek op te halen op basis van ID
app.MapGet("/books/{id:guid}", async (Guid id, IBookService bookService) =>
{
var result = await bookService.GetBookByIdAsync(id);
return result != null ? Results.Ok(result) : Results.NotFound();
});
// Eindpunt om een boek bij te werken op basis van ID
app.MapPut("/books/{id:guid}", async (Guid id, UpdateBookRequest updateBookRequest, IBookService bookService) =>
{
var result = await bookService.UpdateBookAsync(id, updateBookRequest);
return result != null ? Results.Ok(result) : Results.NotFound();
});
// Eindpunt om een boek op basis van ID te verwijderen
app.MapDelete("/books/{id:guid}", async (Guid id, IBookService bookService) =>
{
var result = await bookService.DeleteBookAsync(id);
return result ? Results.NoContent() : Results.NotFound();
});
return app;
}
}
}
Gefeliciteerd! U heeft alle eindpunten voor de boek-API aangemaakt. De eindpunten behandelen de CRUD-bewerkingen voor boeken en retourneren de passende reacties op basis van het verzoek en de gegevens.
Hoe de eindpunten te registreren
Na het definiëren van de API-eindpunten voor de boek-API, is de volgende stap om deze eindpunten te registreren in het Program.cs
-bestand. We zullen de MapBookEndpoints
-methode gebruiken om de boekeindpunten te registreren.
We moeten ook onze Program.cs
-klasse opruimen om ervoor te zorgen dat deze georganiseerd en onderhoudbaar blijft.
// Program.cs
using System.Reflection;
using bookapi_minimal.Endpoints;
using bookapi_minimal.Services;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder(args);
builder.AddApplicationServices();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c=>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Mimal API", Version = "v1", Description = "Showing how you can build minimal " +
"api with .net" });
// Stel het pad voor de Swagger JSON en UI in.
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
});
var app = builder.Build();
// Configureer de HTTP-verzoek-pijplijn.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseExceptionHandler();
app.MapGroup("/api/v1/")
.WithTags(" Book endpoints")
.MapBookEndPoint();
app.Run();
Laten we de belangrijkste onderdelen van het Program.cs
-bestand uiteenzetten:
-
AddApplicationServices: Deze methode registreert de benodigde services voor de API. Het is een extensiemethode die we eerder hebben gemaakt om services toe te voegen aan de dependency injection-container.
-
AddSwaggerGen: Deze methode registreert de Swagger-generator, die wordt gebruikt om de Swagger-documentatie voor de API te maken. We specificeren de titel, versie en beschrijving van de API in het Swagger-document.
-
MapGroup: Deze methode groepeert de eindpunten. Het neemt een pad als parameter en retourneert een
IEndpointRouteBuilder
-object. We gebruiken de methodeWithTags
om tags toe te voegen aan de eindpunten en de methodeMapBookEndpoints
om de boekeindpunten te registreren. -
Run: Deze methode start de toepassing.
Om Swagger-documentatie in te schakelen, moet je de eigenschap GenerateDocumentationFile
toevoegen aan je .csproj
-bestand. In dit voorbeeld is het bestand genaamd bookapi-minimal.csproj
, maar de naam kan variëren afhankelijk van je project.
Voeg de volgende regel toe aan je .csproj
-bestand:
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
Aan het einde zou bookapi-minimal.csproj er als volgt uit moeten zien:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<RootNamespace>bookapi_minimal</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.9.2" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.8" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.8">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
</Project>
Nu we de boekeindpunten hebben geregistreerd in het bestand Program.cs
, kunnen we de toepassing uitvoeren en de API-eindpunten testen met Swagger.
Wanneer u de toepassing uitvoert, zou u de Swagger-documentatie moeten zien op de volgende URL: https://localhost:5001/swagger/index.html
. De Swagger-documentatie biedt informatie over de API-eindpunten, verzoek- en antwoordmodellen, en stelt u in staat om de eindpunten rechtstreeks vanuit de browser te testen. U zou iets dergelijks moeten zien:
Gefeliciteerd! U heeft de bedrijfslogica geïmplementeerd voor de boekenservice, aangepaste uitzonderingen gemaakt, API-eindpunten gedefinieerd, en de eindpunten geregistreerd in het Program.cs
bestand. U heeft ook Swagger-documentatie ingeschakeld om de API-eindpunten te testen.
Hoe u zaaidata aan de database toevoegt
Nog een belangrijke stap is om bij het starten van de toepassing zaaidata aan de database toe te voegen. Deze zaaidata zal de database vullen, zodat u uw API-eindpunten kunt testen zonder handmatig gegevens toe te voegen.
Laten we wat zaaidata toevoegen voordat we migraties uitvoeren en onze API-eindpunten testen.
Om dit te bereiken, zullen we een nieuwe klasse maken in onze Configuratie map genaamd BookTypeConfigurations
en de volgende code toevoegen:
using bookapi_minimal.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace bookapi_minimal.Configurations
{
public class BookTypeConfigurations : IEntityTypeConfiguration<BookModel>
{
public void Configure(EntityTypeBuilder<BookModel> builder)
{
// Configureer de tabelnaam
builder.ToTable("Books");
// Configureer de primaire sleutel
builder.HasKey(x => x.Id);
// Configureer eigenschappen
builder.Property(x => x.Id).ValueGeneratedOnAdd();
builder.Property(x => x.Title).IsRequired().HasMaxLength(100);
builder.Property(x => x.Author).IsRequired().HasMaxLength(100);
builder.Property(x => x.Description).IsRequired().HasMaxLength(500);
builder.Property(x => x.Category).IsRequired().HasMaxLength(100);
builder.Property(x => x.Language).IsRequired().HasMaxLength(50);
builder.Property(x => x.TotalPages).IsRequired();
// Zaaidata
builder.HasData(
new BookModel
{
Id = Guid.NewGuid(),
Title = "The Alchemist",
Author = "Paulo Coelho",
Description = "The Alchemist follows the journey of an Andalusian shepherd",
Category = "Fiction",
Language = "English",
TotalPages = 208
},
new BookModel
{
Id = Guid.NewGuid(),
Title = "To Kill a Mockingbird",
Author = "Harper Lee",
Description = "A novel about the serious issues of rape and racial inequality.",
Category = "Fiction",
Language = "English",
TotalPages = 281
},
new BookModel
{
Id = Guid.NewGuid(),
Title = "1984",
Author = "George Orwell",
Description = "A dystopian social science fiction novel and cautionary tale about the dangers of totalitarianism. ",
Category = "Fiction",
Language = "English",
TotalPages = 328
}
);
}
}
}
Laten we de bovenstaande code uitsplitsen:
In Entity Framework Core kun je de interface IEntityTypeConfiguration
gebruiken om het entiteitstype en seed-gegevens voor de database te configureren. De klasse BookTypeConfigurations
implementeert de interface IEntityTypeConfiguration<BookModel>
en biedt de configuratie voor de entiteit BookModel
.
-
Configure Methode: Deze methode wordt gebruikt om het entiteitstype
BookModel
te configureren. Het definieert de tabelnaam, primaire sleutel en eigenschappen voor de entiteitBookModel
.-
Tabelnaam: De methode
ToTable
specificeert de naam van de tabel die in de database moet worden aangemaakt. In dit geval is de tabelnaam ingesteld op “Books”. -
Primaire Sleutel: De methode
HasKey
specificeert de primaire sleutel voor de entiteitBookModel
. De primaire sleutel is ingesteld op de eigenschapId
. -
Eigenschappen: De methode
Property
configureert de eigenschappen van de entiteitBookModel
. Het specificeert het gegevenstype, lengte en beperkingen voor elke eigenschap.
-
-
Seedgegevens: De
HasData
methode voegt initiële gegevens toe aan de database. Het maakt drieBookModel
objecten aan met voorbeeldgegevens voor het testen van de API-eindpunten.
Nu we de klasse BookTypeConfigurations
hebben aangemaakt, moeten we deze configuratie registreren in de klasse ApplicationContext
. Dit zorgt ervoor dat de configuratie wordt toegepast wanneer de database wordt aangemaakt of gemigreerd.
We zijn eindelijk bijna klaar om onze API te testen. Maar voordat we dat doen, moeten we migraties uitvoeren om de database te maken en de seed-gegevens toe te passen.
Onthoud dat we onze databaseverbindingssnaren in het appsettings.json
bestand hebben toegevoegd? Laten we nu een migratie uitvoeren en later onze database bijwerken zodat de migratie van kracht wordt.
Hoe voer je een migratie uit
Migraties stellen je in staat om het databaseschema bij te werken op basis van wijzigingen in je modelklassen. In Entity Framework Core kun je de dotnet ef migrations add
opdracht gebruiken om een nieuwe migratie te maken die deze wijzigingen weerspiegelt.
Voer de volgende opdracht uit in de terminal om een migratie uit te voeren:
dotnet ef migrations add InitialCreate
Als de opdracht succesvol is, zou je een uitvoer moeten zien die vergelijkbaar is met deze:
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'
Je zult nu een nieuwe map genaamd Migraties
in je project zien. Deze map bevat de migratiebestanden die zijn gemaakt op basis van de wijzigingen in je modelklassen. Deze migratiebestanden bevatten de SQL-opdrachten die nodig zijn om het databaseschema bij te werken.
Hoe de Database bijwerken
Na het maken van de migratie, moet je de migratie toepassen om het databaseschema bij te werken. Je kunt de dotnet ef database update
opdracht gebruiken om de migratie toe te passen en de database bij te werken. Zorg ervoor dat de SQL Server actief is.
Voer de volgende opdracht uit in de terminal:
dotnet ef database update
Dit zal het databaseschema bijwerken op basis van de wijzigingen in je modelklassen. Zorg ervoor dat er geen fouten zijn in je databaseverbindingssnaar.
Hoe de API-eindpunten testen
Nu kunnen we onze endpoints testen met behulp van Swagger. Voer de toepassing uit door het volgende commando in de terminal uit te voeren:
dotnet run
Dit zal onze toepassing uitvoeren. U kunt uw browser openen en naar https://localhost:5001/swagger/index.html
navigeren om toegang te krijgen tot de Swagger-documentatie. U zou een lijst met API-eindpunten, verzoek- en reactiemodellen moeten zien, en de mogelijkheid om de eindpunten rechtstreeks vanuit de browser te testen.
Als uw poortnummer verschilt van 5001
, maakt u zich geen zorgen – het zal nog steeds werken. Het poortnummer kan veranderen afhankelijk van het type machine dat u gebruikt, maar het zal nog steeds hetzelfde resultaat opleveren.
Hoe u het eindpunt Alle boeken ophalen
kunt testen
Volg deze stappen om het eindpunt Alle boeken ophalen
te testen:
-
Klik in de Swagger-documentatie op het eindpunt
GET /api/v1/books
. -
Klik op de knop
Uitproberen
. -
Klik op de knop
Uitvoeren
.
Dit zal een verzoek naar de API sturen om alle boeken in de database op te halen.
U zou de reactie van de API moeten zien, waarin de lijst met boeken staat die in de database zijn toegevoegd.
De onderstaande afbeelding toont de reactie van de API:
Hoe de eindpunt Get Book by ID
te testen
Om het eindpunt Get Book by ID
te testen, volg deze stappen:
-
In de Swagger-documentatie, klik op het eindpunt
GET /api/v1/books/{id}
. -
Voer het ID van een boek in het veld
id
in. U kunt een van de boek-IDs gebruiken die in de database zijn ingevoerd. -
Klik op de knop
Probeer het uit
.
Dit zal een verzoek naar de API sturen om het boek met het gespecificeerde ID op te halen. U zou de respons van de API moeten zien, die het boek met het gespecificeerde ID zal bevatten.
De onderstaande afbeelding toont de respons van de API:
Hoe de eindpunt Add Book
te testen
Om het eindpunt Add Book
te testen, volg deze stappen:
-
In de Swagger-documentatie, klik op het eindpunt
POST /api/v1/books
. -
Klik op de knop
Probeer het uit
. -
Voer de boekgegevens in het verzoeklichaam in.
-
Klik op de
Uitvoeren
knop.
Dit zal een verzoek naar de API sturen om een nieuw boek aan de database toe te voegen.
Je zou de respons van de API moeten zien, waarin het zojuist aangemaakte boek wordt vermeld.
De onderstaande afbeelding toont de respons van de API:
Hoe de Boek Bijwerken
Eindpunt te Testen
Om het Boek Bijwerken
eindpunt te testen, volg deze stappen:
-
In de Swagger-documentatie, klik op het
PUT /api/v1/books/{id}
eindpunt. -
Vul de ID van een boek in het
id
veld in. Je kunt de id van een van de zojuist toegevoegde boeken gebruiken. -
Klik op de
Probeer het uit
knop.
Dit zal een verzoek naar de API sturen om het boek met de gespecificeerde ID bij te werken.
Je zou de respons van de API moeten zien, waarin het bijgewerkte boek wordt vermeld.
De onderstaande afbeelding toont de respons van de API:
Hoe de Boek Verwijderen
Eindpunt te Testen
Om het Boek Verwijderen
eindpunt te testen, volg deze stappen:
-
In de Swagger-documentatie, klik op het
DELETE /api/v1/books/{id}
eindpunt. -
Voer het ID van een boek in het veld
id
in. U kunt een van de ID’s van de boeken die we zojuist hebben toegevoegd of de gezaaide gegevens gebruiken. -
Klik op de knop
Probeer het uit
.
Dit zal een verzoek naar de API sturen om het boek met het gespecificeerde ID te verwijderen.
De onderstaande afbeelding toont de reactie van de API:
Gefeliciteerd! U heeft alle CRUD-operaties voor boeken geïmplementeerd en de API-eindpunten getest met Swagger, waarbij is geverifieerd dat ze werken zoals verwacht. U kunt nu voortbouwen op deze basis om meer functies en functionaliteiten aan uw API toe te voegen.
Conclusie
Deze handleiding onderzocht hoe u een minimale API kunt maken in ASP.NET Core met .NET 8. We hebben een uitgebreide boeken-API gebouwd die CRUD-operaties ondersteunt, aangepaste uitzonderingen geïmplementeerd, API-eindpunten gedefinieerd en geregistreerd, en Swagger-documentatie ingeschakeld voor eenvoudig testen.
Door deze tutorial te volgen, heeft u een solide basis gelegd voor het bouwen van minimale API’s met ASP.NET Core. U kunt deze kennis nu toepassen en robuuste API’s maken voor verschillende domeinen en industrieën.
Ik hoop dat u deze tutorial zowel nuttig als informatief vond. Bedankt voor het lezen!
Voel u vrij om contact met mij op te nemen via sociale media:
Source:
https://www.freecodecamp.org/news/create-a-minimal-api-in-net-core-handbook/