Delen via


Zelfstudie: Een web-API op basis van een controller maken met ASP.NET Core

Note

Dit is niet de nieuwste versie van dit artikel. Zie de .NET 9-versie van dit artikel voor de huidige release.

Warning

Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie het .NET- en .NET Core-ondersteuningsbeleid voor meer informatie. Zie de .NET 9-versie van dit artikel voor de huidige release.

Important

Deze informatie heeft betrekking op een pre-releaseproduct dat aanzienlijk kan worden gewijzigd voordat het commercieel wordt uitgebracht. Microsoft geeft geen garanties, uitdrukkelijk of impliciet, met betrekking tot de informatie die hier wordt verstrekt.

Zie de .NET 9-versie van dit artikel voor de huidige release.

By Tim Deschryver and Rick Anderson

In deze zelfstudie leert u de basisbeginselen van het bouwen van een web-API op basis van een controller die gebruikmaakt van een database. Another approach to creating APIs in ASP.NET Core is to create minimal APIs. For help with choosing between minimal APIs and controller-based APIs, see APIs overview. Zie zelfstudie: Een minimale API maken met ASP.NET Core voor een zelfstudie over het maken van een minimale API.

Overview

In deze tutorial maak je de volgende API aan:

API Description Request body Response body
GET /api/todoitems Alle to-do items ophalen None Reeks van to-do items
GET /api/todoitems/{id} Een item ophalen met ID None To-do item
POST /api/todoitems Een nieuw item toevoegen To-do item To-do item
PUT /api/todoitems/{id} Een bestaand item bijwerken To-do item None
DELETE /api/todoitems/{id}     Een item verwijderen None None

In het volgende diagram ziet u het ontwerp van de app.

De client wordt vertegenwoordigd door een vak aan de linkerkant. Het verzendt een aanvraag en ontvangt een antwoord van de toepassing, een vak aan de rechterkant. In het toepassingsvak vertegenwoordigen drie vakken de controller, het model en de gegevenstoegangslaag. De aanvraag wordt geleverd in de controller van de toepassing en lees-/schrijfbewerkingen worden uitgevoerd tussen de controller en de gegevenstoegangslaag. Het model wordt geserialiseerd en geretourneerd naar de client in het antwoord.

Prerequisites

Een web-API-project maken

  • From the File menu, select New>Project.
  • Enter Web API in the search box.
  • Selecteer de ASP.NET Core Web API-sjabloon en selecteer Volgende.
  • Geef in het dialoogvenster Uw nieuwe project configureren de naam van het project TodoApi en selecteer Volgende.
  • In the Additional information dialog:
    • Confirm the Framework is .NET 9.0 (Standard Term Support).
    • Controleer of het selectievakje voor OpenAPI-ondersteuning inschakelen is ingeschakeld.
    • Controleer of het selectievakje voor Controllers gebruiken (schakel het selectievakje uit om minimale API's te gebruiken) is ingeschakeld.
    • Select Create.

Een NuGet-pakket toevoegen

Er moet een NuGet-pakket worden toegevoegd ter ondersteuning van de database die in deze zelfstudie wordt gebruikt.

  • From the Tools menu, select NuGet Package Manager > Manage NuGet Packages for Solution.
  • Select the Browse tab.
  • Enter Microsoft.EntityFrameworkCore.InMemory in the search box, and then select Microsoft.EntityFrameworkCore.InMemory.
  • Select the Project checkbox in the right pane and then select Install.

Note

Zie de artikelen onder Pakketten installeren en beheren bij Pakketconsumptieworkflow (NuGet-documentatie) voor hulp bij het toevoegen van pakketten aan .NET-apps. Confirm correct package versions at NuGet.org.

Het project uitvoeren

The project template creates a WeatherForecast API with support for OpenAPI.

Druk op Ctrl+F5 om uit te voeren zonder het foutopsporingsprogramma.

Visual Studio geeft het volgende dialoogvenster weer wanneer een project nog niet is geconfigureerd voor het gebruik van SSL:

Dit project is geconfigureerd voor het gebruik van SSL. Als u SSL-waarschuwingen in de browser wilt voorkomen, kunt u ervoor kiezen om het zelfondertekende certificaat te vertrouwen dat IIS Express heeft gegenereerd. Wilt u het IIS Express SSL-certificaat vertrouwen?

Select Yes if you trust the IIS Express SSL certificate.

Het volgende dialoogvenster wordt weergegeven:

Dialoogvenster Beveiligingswaarschuwing

Select Yes if you agree to trust the development certificate.

Zie Firefox SEC_ERROR_INADEQUATE_KEY_USAGE certificaatfout voor meer informatie over het vertrouwen van de Firefox-browser.

Visual Studio start een terminalvenster en geeft de URL van de actieve app weer. De API wordt gehost op https://localhost:<port>, waarbij <port> een willekeurig gekozen poortnummer is dat is ingesteld bij het maken van het project.

...
info: Microsoft.Hosting.Lifetime[14]
   Now listening on: https://localhost:7260
info: Microsoft.Hosting.Lifetime[14]
   Now listening on: http://localhost:7261
info: Microsoft.Hosting.Lifetime[0]
   Application started. Press Ctrl+C to shut down.
...

Ctrl+click the HTTPS URL in the output to test the web app in a browser. Er is geen eindpunt op https://localhost:<port>, dus de browser retourneert HTTP 404 Niet gevonden.

Voeg /weatherforecast toe aan de URL om de WeatherForecast-API te testen. In de browser wordt JSON weergegeven die vergelijkbaar is met het volgende voorbeeld:

[
    {
        "date": "2025-07-16",
        "temperatureC": 52,
        "temperatureF": 125,
        "summary": "Mild"
    },
    {
        "date": "2025-07-17",
        "temperatureC": 36,
        "temperatureF": 96,
        "summary": "Warm"
    },
    {
        "date": "2025-07-18",
        "temperatureC": 39,
        "temperatureF": 102,
        "summary": "Cool"
    },
    {
        "date": "2025-07-19",
        "temperatureC": 10,
        "temperatureF": 49,
        "summary": "Bracing"
    },
    {
        "date": "2025-07-20",
        "temperatureC": -1,
        "temperatureF": 31,
        "summary": "Chilly"
    }
]

Het project testen

In deze zelfstudie worden Endpoints Explorer- en HTTP-bestanden gebruikt om de API te testen.

Een modelklasse toevoegen

A model is a set of classes that represent the data that the app manages. Het model voor deze app is de TodoItem klasse.

  • In Solution Explorer, right-click the project. Select Add>New Folder. Geef de map een naam Models.
  • Right-click the Models folder and select Add>Class. Name the class TodoItem and select Add.
  • Vervang de sjablooncode door het volgende:
namespace TodoApi.Models;

public class TodoItem
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

De eigenschap Id fungeert als de unieke sleutel in een relationele database.

Modelklassen kunnen overal in het project worden gebruikt, maar de map Models wordt standaard gebruikt.

Een databasecontext toevoegen

The database context is the main class that coordinates Entity Framework functionality for a data model. Deze klasse wordt gemaakt door te erven van de Microsoft.EntityFrameworkCore.DbContext klasse.

  • Right-click the Models folder and select Add>Class. Name the class TodoContext and click Add.

  • Voer de volgende code in:

    using Microsoft.EntityFrameworkCore;
    
    namespace TodoApi.Models;
    
    public class TodoContext : DbContext
    {
        public TodoContext(DbContextOptions<TodoContext> options)
            : base(options)
        {
        }
    
        public DbSet<TodoItem> TodoItems { get; set; } = null!;
    }
    

De databasecontext registreren

In ASP.NET Core moeten services zoals de DB-context worden geregistreerd bij de afhankelijkheidsinjectiecontainer (DI ). De container biedt de service aan controllers.

Werk Program.cs bij met de volgende gemarkeerde code:

using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddOpenApi();
builder.Services.AddDbContext<TodoContext>(opt =>
    opt.UseInMemoryDatabase("TodoList"));

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.MapOpenApi();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

De voorgaande code:

  • Voegt using richtlijnen toe.
  • Voegt de databasecontext toe aan de DI-container.
  • Hiermee geeft u op dat de databasecontext een in-memory database gebruikt.

Genereer een controller

  • Klik met de rechtermuisknop op de map Controllers.

  • Select Add>New Scaffolded Item.

  • Selecteer API-controller met acties, met behulp van Entity Framework en selecteer vervolgens Toevoegen.

  • In het dialoogvenster API-controller toevoegen met acties, met behulp van Entity Framework:

    • Select TodoItem (TodoApi.Models) in the Model class.
    • Select TodoContext (TodoApi.Models) in the Data context class.
    • Select Add.

    If the scaffolding operation fails, select Add to try scaffolding a second time.

Met deze stap worden de Microsoft.VisualStudio.Web.CodeGeneration.Design- en Microsoft.EntityFrameworkCore.Tools NuGet-pakketten aan het project toegevoegd. Deze pakketten zijn vereist voor steigerbouw.

De gegenereerde code:

  • Markeert de klasse met het kenmerk [ApiController]. Dit kenmerk geeft aan dat de controller reageert op web-API-aanvragen. Zie Web-API's maken met ASP.NET Core voor informatie over specifiek gedrag dat het kenmerk inschakelt.
  • Maakt gebruik van DI om de databasecontext (TodoContext) in de controller te injecteren. The database context is used in each of the CRUD methods in the controller.

De ASP.NET Core-sjablonen voor:

  • Controllers met weergaven bevatten [action] in de routesjabloon.
  • API-controllers bevatten geen [action] in de routesjabloon.

When the [action] token isn't in the route template, the action name (method name) isn't included in the endpoint. Dat wil gezegd: de naam van de gekoppelde methode van de actie wordt niet gebruikt in de overeenkomende route.

De methode voor het aanmaken van PostTodoItem bijwerken

Update the return statement in the PostTodoItem to use the nameof operator:

[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
    _context.TodoItems.Add(todoItem);
    await _context.SaveChangesAsync();

    //    return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
    return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}

De voorgaande code is een HTTP POST methode, zoals aangegeven door het kenmerk [HttpPost]. Met de methode wordt de waarde van de TodoItem opgehaald uit de hoofdtekst van de HTTP-aanvraag.

Zie Kenmerkroutering met http[werkwoord]-kenmerken voor meer informatie.

De methode CreatedAtAction:

  • Retourneert een HTTP 201-statuscode als dit lukt. HTTP 201 is het standaardantwoord voor een HTTP POST methode waarmee een nieuwe resource op de server wordt gemaakt.
  • Adds a Location header to the response. The Location header specifies the URI of the newly created to-do item. Zie 10.2.2 2 201 Gemaakt voor meer informatie.
  • Verwijst naar de GetTodoItem actie om de URI van de Location header te maken. Het trefwoord C# nameof wordt gebruikt om te voorkomen dat de actienaam in de CreatedAtAction aanroep hard wordt gecodeerd.

Test PostTodoItem

  • Select View>Other Windows>Endpoints Explorer.

  • Right-click the POST endpoint and select Generate request.

    Het contextmenu van Endpoints Explorer waarin het menu-item Aanvraag genereren is gemarkeerd.

    Er wordt een nieuw bestand gemaakt in de projectmap met de naam TodoApi.http, met inhoud die vergelijkbaar is met het volgende voorbeeld:

    @TodoApi_HostAddress = https://localhost:49738
    
    POST {{TodoApi_HostAddress}}/api/todoitems
    Content-Type: application/json
    
    {
      //TodoItem
    }
    
    ###
    
    • Met de eerste regel maakt u een variabele die wordt gebruikt voor alle eindpunten.
    • De volgende regel definieert een POST-aanvraag.
    • De regels na de POST-aanvraagregel definiëren de headers en een tijdelijke aanduiding voor de aanvraagbody.
    • De regel met de drievoudige hashtag (###) is een scheidingsteken voor aanvragen: wat erna komt, is voor een andere aanvraag.
  • De POST-aanvraag verwacht een TodoItem. Om de todo te definiëren, vervangt u de //TodoItem opmerking door de volgende JSON:

    {
      "name": "walk dog",
      "isComplete": true
    }
    

    Het todoApi.http-bestand moet er nu uitzien zoals in het volgende voorbeeld, maar met uw poortnummer:

    @TodoApi_HostAddress = https://localhost:7260
    
    Post {{TodoApi_HostAddress}}/api/todoitems
    Content-Type: application/json
    
    {
      "name": "walk dog",
      "isComplete": true
    }
    
    ###
    
  • Voer de app uit.

  • Select the Send request link that is above the POST request line.

    .HTTP-bestandenvenster met 'uitvoeren'-link gemarkeerd.

    The POST request is sent to the app and the response is displayed in the Response pane.

    .http-bestandvenster met reactie van de POST-aanvraag.

De URI van de locatieheader testen

Test the app by calling the GET endpoints from a browser or by using Endpoints Explorer. The following steps are for Endpoints Explorer.

  • In Endpoints Explorer, right-click the first GET endpoint, and select Generate request.

    De volgende inhoud wordt toegevoegd aan het TodoApi.http-bestand:

    GET {{TodoApi_HostAddress}}/api/todoitems
    
    ###
    
  • Select the Send request link that is above the new GET request line.

    The GET request is sent to the app and the response is displayed in the Response pane.

  • De hoofdtekst van het antwoord is vergelijkbaar met de volgende JSON:

    [
      {
        "id": 1,
        "name": "walk dog",
        "isComplete": true
      }
    ]
    
  • In Endpoints Explorer, right-click the /api/todoitems/{id}GET endpoint and select Generate request. De volgende inhoud wordt toegevoegd aan het TodoApi.http-bestand:

    @id=0
    GET {{TodoApi_HostAddress}}/api/todoitems/{{id}}
    
    ###
    
  • Wijs {@id} toe aan 1 (in plaats van 0).

  • Select the Send request link that is above the new GET request line.

    The GET request is sent to the app and the response is displayed in the Response pane.

  • De hoofdtekst van het antwoord is vergelijkbaar met de volgende JSON:

    {
      "id": 1,
      "name": "walk dog",
      "isComplete": true
    }
    

De GET-methoden onderzoeken

Er worden twee GET-eindpunten geïmplementeerd:

  • GET /api/todoitems
  • GET /api/todoitems/{id}

In de vorige sectie is een voorbeeld van de /api/todoitems/{id} route getoond.

Follow the POST instructions to add another todo item, and then test the /api/todoitems route using Swagger.

Deze app maakt gebruik van een in-memory database. Als de app is gestopt en gestart, retourneert de voorgaande GET-aanvraag geen gegevens. If no data is returned, POST data to the app.

Routering en URL-paden

Het kenmerk [HttpGet] geeft een methode aan die reageert op een HTTP GET aanvraag. Het URL-pad voor elke methode wordt als volgt samengesteld:

  • Begin met de sjabloontekenreeks in het kenmerk Route van de controller:

    [Route("api/[controller]")]
    [ApiController]
    public class TodoItemsController : ControllerBase
    
  • Vervang [controller] door de naam van de controller. Dit is de naam van de controllerklasse minus het achtervoegsel 'Controller'. For this sample, the controller class name is TodoItemsController, so the controller name is "TodoItems". ASP.NET Core routing is case insensitive.

  • Als het kenmerk [HttpGet] een routesjabloon heeft (bijvoorbeeld [HttpGet("products")]), voegt u dit toe aan het pad. In dit voorbeeld wordt geen sjabloon gebruikt. Zie Kenmerkroutering met http[werkwoord]-kenmerken voor meer informatie.

In de volgende GetTodoItem-methode is "{id}" een placeholder voor de unieke identificatie van het item to-do. Wanneer GetTodoItem wordt aangeroepen, wordt de waarde van "{id}" in de URL verstrekt aan de methode in de parameter id.

[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return todoItem;
}

Return values

Het retourtype van de GetTodoItems en GetTodoItem methoden is ActionResult<T-type>. ASP.NET Core automatically serializes the object to JSON and writes the JSON into the body of the response message. The response code for this return type is 200 OK, assuming there are no unhandled exceptions. Niet-verwerkte uitzonderingen worden omgezet in 5xx-fouten.

ActionResult retourtypen kunnen een breed scala aan HTTP-statuscodes vertegenwoordigen. GetTodoItem kan bijvoorbeeld twee verschillende statuswaarden retourneren:

  • If no item matches the requested ID, the method returns a 404 statusNotFound error code.
  • Anders retourneert de methode 200 met een JSON-antwoordtekst. Het retourneren van item resulteert in een HTTP 200 antwoord.

De methode PutTodoItem

Bekijk de PutTodoItem methode:

[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
    if (id != todoItem.Id)
    {
        return BadRequest();
    }

    _context.Entry(todoItem).State = EntityState.Modified;

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!TodoItemExists(id))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return NoContent();
}

PutTodoItem is vergelijkbaar met PostTodoItem, met uitzondering van HTTP PUT. Het antwoord is 204 (geen inhoud). Volgens de HTTP-specificatie vereist een PUT aanvraag dat de client de volledige bijgewerkte entiteit verzendt, niet alleen de wijzigingen. To support partial updates, use HTTP PATCH.

De methode PutTodoItem testen

In dit voorbeeld wordt een in-memory database gebruikt die telkens wanneer de app wordt gestart, moet worden geïnitialiseerd. Er moet een item in de database staan voordat u een PUT-aanroep uitvoert. Roep GET aan om ervoor te zorgen dat er een item in de database staat voordat u een PUT-aanroep doet.

Gebruik de methode PUT om de TodoItem met id = 1 bij te werken en de naam ervan in te stellen op "feed fish". Let op: het antwoord is HTTP 204 No Content.

  • In Endpoints Explorer, right-click the PUT endpoint, and select Generate request.

    De volgende inhoud wordt toegevoegd aan het TodoApi.http-bestand:

    PUT {{TodoApi_HostAddress}}/api/todoitems/{{id}}
    Content-Type: application/json
    
    {
      //TodoItem
    }
    
    ###
    
  • Vervang {{id}} in de PUT-aanvraagregel door 1.

  • Vervang de tijdelijke aanduiding //TodoItem door de volgende regels:

    PUT {{TodoApi_HostAddress}}/api/todoitems/1
    Content-Type: application/json
    
    {
      "id": 1,
      "name": "feed fish",
      "isComplete": false
    }
    
  • Select the Send request link that is above the new PUT request line.

    The PUT request is sent to the app and the response is displayed in the Response pane. De hoofdtekst van het antwoord is leeg en de statuscode is 204.

De methode DeleteTodoItem

Bekijk de DeleteTodoItem methode:

[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);
    if (todoItem == null)
    {
        return NotFound();
    }

    _context.TodoItems.Remove(todoItem);
    await _context.SaveChangesAsync();

    return NoContent();
}

De methode DeleteTodoItem testen

Gebruik de methode DELETE om de TodoItem met id = 1 te verwijderen. Let op: het antwoord is HTTP 204 No Content.

  • In Endpoints Explorer, right-click the DELETE endpoint and select Generate request.

    Er wordt een DELETE-aanvraag toegevoegd aan TodoApi.http.

  • Vervang {{id}} in de regel van de DELETE-aanvraag door 1. De DELETE-aanvraag moet eruitzien als in het volgende voorbeeld:

    DELETE {{TodoApi_HostAddress}}/api/todoitems/{{id}}
    
    ###
    
  • Select the Send request link for the DELETE request.

    The DELETE request is sent to the app and the response is displayed in the Response pane. De hoofdtekst van het antwoord is leeg en de statuscode is 204.

Testen met andere hulpprogramma's

Er zijn veel andere hulpprogramma's die kunnen worden gebruikt om web-API's te testen, bijvoorbeeld:

Prevent over-posting

Op dit moment wordt in de voorbeeld-app het hele TodoItem-object weergegeven. Productie-apps beperken doorgaans de gegevens die worden ingevoerd en geretourneerd met behulp van een subset van het model. Er zijn meerdere redenen achter dit, en beveiliging is een belangrijke. De subset van een model wordt meestal aangeduid als een DTO (Data Transfer Object), invoermodel of weergavemodel. DTO is used in this tutorial.

Een DTO kan worden gebruikt voor het volgende:

  • Prevent over-posting.
  • Eigenschappen verbergen die klanten niet zouden moeten zien.
  • Laat bepaalde eigenschappen weg om de nettolading te verkleinen.
  • Maak objectgrafieken plat die geneste objecten bevatten. Platgemaakte objectgrafieken kunnen handiger zijn voor clients.

Als u de DTO-benadering wilt demonstreren, werkt u de TodoItem klasse bij om een geheim veld op te nemen:

namespace TodoApi.Models;

public class TodoItem
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
    public string? Secret { get; set; }
}

Het geheime veld moet worden verborgen voor deze app, maar een beheer-app kan ervoor kiezen om het beschikbaar te maken.

Controleer of u de geheime veldgegevens kunt plaatsen en ophalen.

Create a DTO model in a Models/TodoItemsDTO.cs file:

namespace TodoApi.Models;

public class TodoItemDTO
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

Werk de TodoItemsController bij om TodoItemDTOte gebruiken:

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

namespace TodoApi.Controllers;

[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
    private readonly TodoContext _context;

    public TodoItemsController(TodoContext context)
    {
        _context = context;
    }

    // GET: api/TodoItems
    [HttpGet]
    public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
    {
        return await _context.TodoItems
            .Select(x => ItemToDTO(x))
            .ToListAsync();
    }

    // GET: api/TodoItems/5
    // <snippet_GetByID>
    [HttpGet("{id}")]
    public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);

        if (todoItem == null)
        {
            return NotFound();
        }

        return ItemToDTO(todoItem);
    }
    // </snippet_GetByID>

    // PUT: api/TodoItems/5
    // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
    // <snippet_Update>
    [HttpPut("{id}")]
    public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
    {
        if (id != todoDTO.Id)
        {
            return BadRequest();
        }

        var todoItem = await _context.TodoItems.FindAsync(id);
        if (todoItem == null)
        {
            return NotFound();
        }

        todoItem.Name = todoDTO.Name;
        todoItem.IsComplete = todoDTO.IsComplete;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
        {
            return NotFound();
        }

        return NoContent();
    }
    // </snippet_Update>

    // POST: api/TodoItems
    // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
    // <snippet_Create>
    [HttpPost]
    public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
    {
        var todoItem = new TodoItem
        {
            IsComplete = todoDTO.IsComplete,
            Name = todoDTO.Name
        };

        _context.TodoItems.Add(todoItem);
        await _context.SaveChangesAsync();

        return CreatedAtAction(
            nameof(GetTodoItem),
            new { id = todoItem.Id },
            ItemToDTO(todoItem));
    }
    // </snippet_Create>

    // DELETE: api/TodoItems/5
    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);
        if (todoItem == null)
        {
            return NotFound();
        }

        _context.TodoItems.Remove(todoItem);
        await _context.SaveChangesAsync();

        return NoContent();
    }

    private bool TodoItemExists(long id)
    {
        return _context.TodoItems.Any(e => e.Id == id);
    }

    private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
       new TodoItemDTO
       {
           Id = todoItem.Id,
           Name = todoItem.Name,
           IsComplete = todoItem.IsComplete
       };
}

Controleer of u het geheime veld niet kunt posten of ophalen.

De web-API aanroepen met JavaScript

Zie zelfstudie: Een ASP.NET Core-web-API aanroepen met JavaScript.

Web-API-videoserie

Zie video: Beginnersreeks voor: Web-API's.

Patronen voor bedrijfsweb-apps

Zie Enterprise-web-apppatronen voor hulp bij het maken van een betrouwbare, veilige, performante, testbare en schaalbare ASP.NET Core-app. Er is een volledige voorbeeldweb-app van productiekwaliteit beschikbaar waarmee de patronen worden geïmplementeerd.

Verificatieondersteuning toevoegen aan een web-API

ASP.NET Core Identity voegt de aanmeldingsfunctionaliteit van de gebruikersinterface (UI) toe aan ASP.NET Core-web-apps. Gebruik een van de volgende manieren om web-API's en SPA's te beveiligen:

Duende Identity Server is een OpenID Connect- en OAuth 2.0-framework voor ASP.NET Core. Duende Identity Server maakt de volgende beveiligingsfuncties mogelijk:

  • Verificatie als een service (AaaS)
  • Eenmalige aanmelding/uit (SSO) voor meerdere toepassingstypen
  • Toegangsbeheer voor API's
  • Federation Gateway

Important

Duende Software might require you to pay a license fee for production use of Duende Identity Server. Zie Migreren van ASP.NET Core in .NET 5 naar .NET 6 voor meer informatie.

Zie de documentatie van Duende Server (Duende Identity Software-website) voor meer informatie.

Publiceren naar Azure

Zie quickstart: Een ASP.NET-web-app implementeren voor meer informatie over het implementeren in Azure.

Additional resources

Bekijk of download voorbeeldcode voor deze zelfstudie. Zie hoe te downloaden.

Zie de volgende bronnen voor meer informatie:

In deze zelfstudie leert u de basisbeginselen van het bouwen van een web-API op basis van een controller die gebruikmaakt van een database. Another approach to creating APIs in ASP.NET Core is to create minimal APIs. For help with choosing between minimal APIs and controller-based APIs, see APIs overview. Zie zelfstudie: Een minimale API maken met ASP.NET Core voor een zelfstudie over het maken van een minimale API.

Overview

In deze tutorial maak je de volgende API aan:

API Description Request body Response body
GET /api/todoitems Alle to-do items ophalen None Reeks van to-do items
GET /api/todoitems/{id} Een item ophalen met ID None To-do item
POST /api/todoitems Een nieuw item toevoegen To-do item To-do item
PUT /api/todoitems/{id} Een bestaand item bijwerken To-do item None
DELETE /api/todoitems/{id}     Een item verwijderen None None

In het volgende diagram ziet u het ontwerp van de app.

De client wordt vertegenwoordigd door een vak aan de linkerkant. Het verzendt een aanvraag en ontvangt een antwoord van de toepassing, een vak aan de rechterkant. In het toepassingsvak vertegenwoordigen drie vakken de controller, het model en de gegevenstoegangslaag. De aanvraag wordt geleverd in de controller van de toepassing en lees-/schrijfbewerkingen worden uitgevoerd tussen de controller en de gegevenstoegangslaag. Het model wordt geserialiseerd en geretourneerd naar de client in het antwoord.

Prerequisites

Een webproject maken

  • From the File menu, select New>Project.
  • Enter Web API in the search box.
  • Selecteer de ASP.NET Core Web API-sjabloon en selecteer Volgende.
  • Geef in het dialoogvenster Uw nieuwe project configureren de naam van het project TodoApi en selecteer Volgende.
  • In the Additional information dialog:
    • Confirm the Framework is .NET 8.0 (Long Term Support).
    • Controleer of het selectievakje voor Controllers gebruiken (schakel het selectievakje uit om minimale API's te gebruiken) is ingeschakeld.
    • Controleer of het selectievakje voor OpenAPI-ondersteuning inschakelen is ingeschakeld.
    • Select Create.

Een NuGet-pakket toevoegen

Er moet een NuGet-pakket worden toegevoegd ter ondersteuning van de database die in deze zelfstudie wordt gebruikt.

  • From the Tools menu, select NuGet Package Manager > Manage NuGet Packages for Solution.
  • Select the Browse tab.
  • Enter Microsoft.EntityFrameworkCore.InMemory in the search box, and then select Microsoft.EntityFrameworkCore.InMemory.
  • Select the Project checkbox in the right pane and then select Install.

Note

Zie de artikelen onder Pakketten installeren en beheren bij Pakketconsumptieworkflow (NuGet-documentatie) voor hulp bij het toevoegen van pakketten aan .NET-apps. Confirm correct package versions at NuGet.org.

Het project testen

The project template creates a WeatherForecast API with support for Swagger.

Druk op Ctrl+F5 om uit te voeren zonder het foutopsporingsprogramma.

Visual Studio geeft het volgende dialoogvenster weer wanneer een project nog niet is geconfigureerd voor het gebruik van SSL:

Dit project is geconfigureerd voor het gebruik van SSL. Als u SSL-waarschuwingen in de browser wilt voorkomen, kunt u ervoor kiezen om het zelfondertekende certificaat te vertrouwen dat IIS Express heeft gegenereerd. Wilt u het IIS Express SSL-certificaat vertrouwen?

Select Yes if you trust the IIS Express SSL certificate.

Het volgende dialoogvenster wordt weergegeven:

Dialoogvenster Beveiligingswaarschuwing

Select Yes if you agree to trust the development certificate.

Zie Firefox SEC_ERROR_INADEQUATE_KEY_USAGE certificaatfout voor meer informatie over het vertrouwen van de Firefox-browser.

Visual Studio start de standaardbrowser en gaat naar https://localhost:<port>/swagger/index.html, waarbij <port> een willekeurig gekozen poortnummer is dat is ingesteld bij het maken van het project.

De Swagger-pagina /swagger/index.html wordt weergegeven. Select GET>Try it out>Execute. Op de pagina wordt het volgende weergegeven:

  • The Curl command to test the WeatherForecast API.
  • De URL voor het testen van de WeatherForecast-API.
  • De antwoordcode, hoofdtekst en headers.
  • Een vervolgkeuzelijst met mediatypen en de voorbeeldwaarde en het schema.

Als de Swagger-pagina niet wordt weergegeven, raadpleegt u dit GitHub-probleem.

Swagger wordt gebruikt voor het genereren van nuttige documentatie en Help-pagina's voor web-API's. In deze zelfstudie wordt Swagger gebruikt om de app te testen. Zie ASP.NET Core-web-API-documentatie met Swagger/OpenAPI voor meer informatie over Swagger.

Copy and paste the Request URL in the browser: https://localhost:<port>/weatherforecast

JSON die vergelijkbaar is met het volgende voorbeeld wordt geretourneerd:

[
    {
        "date": "2019-07-16T19:04:05.7257911-06:00",
        "temperatureC": 52,
        "temperatureF": 125,
        "summary": "Mild"
    },
    {
        "date": "2019-07-17T19:04:05.7258461-06:00",
        "temperatureC": 36,
        "temperatureF": 96,
        "summary": "Warm"
    },
    {
        "date": "2019-07-18T19:04:05.7258467-06:00",
        "temperatureC": 39,
        "temperatureF": 102,
        "summary": "Cool"
    },
    {
        "date": "2019-07-19T19:04:05.7258471-06:00",
        "temperatureC": 10,
        "temperatureF": 49,
        "summary": "Bracing"
    },
    {
        "date": "2019-07-20T19:04:05.7258474-06:00",
        "temperatureC": -1,
        "temperatureF": 31,
        "summary": "Chilly"
    }
]

Een modelklasse toevoegen

A model is a set of classes that represent the data that the app manages. Het model voor deze app is de TodoItem klasse.

  • In Solution Explorer, right-click the project. Select Add>New Folder. Geef de map een naam Models.
  • Right-click the Models folder and select Add>Class. Name the class TodoItem and select Add.
  • Vervang de sjablooncode door het volgende:
namespace TodoApi.Models;

public class TodoItem
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

De eigenschap Id fungeert als de unieke sleutel in een relationele database.

Modelklassen kunnen overal in het project worden gebruikt, maar de map Models wordt standaard gebruikt.

Een databasecontext toevoegen

The database context is the main class that coordinates Entity Framework functionality for a data model. Deze klasse wordt gemaakt door te erven van de Microsoft.EntityFrameworkCore.DbContext klasse.

  • Right-click the Models folder and select Add>Class. Name the class TodoContext and click Add.
  • Voer de volgende code in:

    using Microsoft.EntityFrameworkCore;
    
    namespace TodoApi.Models;
    
    public class TodoContext : DbContext
    {
        public TodoContext(DbContextOptions<TodoContext> options)
            : base(options)
        {
        }
    
        public DbSet<TodoItem> TodoItems { get; set; } = null!;
    }
    

De databasecontext registreren

In ASP.NET Core moeten services zoals de DB-context worden geregistreerd bij de afhankelijkheidsinjectiecontainer (DI ). De container biedt de service aan controllers.

Werk Program.cs bij met de volgende gemarkeerde code:

using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddDbContext<TodoContext>(opt =>
    opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

De voorgaande code:

  • Voegt using richtlijnen toe.
  • Voegt de databasecontext toe aan de DI-container.
  • Hiermee geeft u op dat de databasecontext een in-memory database gebruikt.

Genereer een controller

  • Klik met de rechtermuisknop op de map Controllers.

  • Select Add>New Scaffolded Item.

  • Selecteer API-controller met acties, met behulp van Entity Framework en selecteer vervolgens Toevoegen.

  • In het dialoogvenster API-controller toevoegen met acties, met behulp van Entity Framework:

    • Select TodoItem (TodoApi.Models) in the Model class.
    • Select TodoContext (TodoApi.Models) in the Data context class.
    • Select Add.

    If the scaffolding operation fails, select Add to try scaffolding a second time.

De gegenereerde code:

  • Markeert de klasse met het kenmerk [ApiController]. Dit kenmerk geeft aan dat de controller reageert op web-API-aanvragen. Zie Web-API's maken met ASP.NET Core voor informatie over specifiek gedrag dat het kenmerk inschakelt.
  • Maakt gebruik van DI om de databasecontext (TodoContext) in de controller te injecteren. The database context is used in each of the CRUD methods in the controller.

De ASP.NET Core-sjablonen voor:

  • Controllers met weergaven bevatten [action] in de routesjabloon.
  • API-controllers bevatten geen [action] in de routesjabloon.

When the [action] token isn't in the route template, the action name (method name) isn't included in the endpoint. Dat wil gezegd: de naam van de gekoppelde methode van de actie wordt niet gebruikt in de overeenkomende route.

De methode voor het aanmaken van PostTodoItem bijwerken

Update the return statement in the PostTodoItem to use the nameof operator:

[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
    _context.TodoItems.Add(todoItem);
    await _context.SaveChangesAsync();

    //    return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
    return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}

De voorgaande code is een HTTP POST methode, zoals aangegeven door het kenmerk [HttpPost]. Met de methode wordt de waarde van de TodoItem opgehaald uit de hoofdtekst van de HTTP-aanvraag.

Zie Kenmerkroutering met http[werkwoord]-kenmerken voor meer informatie.

De methode CreatedAtAction:

  • Retourneert een HTTP 201-statuscode als dit lukt. HTTP 201 is het standaardantwoord voor een HTTP POST methode waarmee een nieuwe resource op de server wordt gemaakt.
  • Adds a Location header to the response. The Location header specifies the URI of the newly created to-do item. Zie 10.2.2 2 201 Gemaakt voor meer informatie.
  • Verwijst naar de GetTodoItem actie om de URI van de Location header te maken. Het trefwoord C# nameof wordt gebruikt om te voorkomen dat de actienaam in de CreatedAtAction aanroep hard wordt gecodeerd.

Test PostTodoItem

  • Druk op Ctrl+F5 om de app uit te voeren.

  • In the Swagger browser window, select POST /api/TodoItems, and then select Try it out.

  • In the Request body input window, update the JSON. For example,

    {
      "name": "walk dog",
      "isComplete": true
    }
    
  • Select Execute

    Swagger POST

De URI van de locatieheader testen

In the preceding POST, the Swagger UI shows the location header under Response headers. Bijvoorbeeld location: https://localhost:7260/api/TodoItems/1. De locatieheader toont de URI voor de gemaakte resource.

De locatiekoptekst testen:

  • In the Swagger browser window, select GET /api/TodoItems/{id}, and then select Try it out.

  • Enter 1 in the id input box, and then select Execute.

    Swagger GET

De GET-methoden onderzoeken

Er worden twee GET-eindpunten geïmplementeerd:

  • GET /api/todoitems
  • GET /api/todoitems/{id}

In de vorige sectie is een voorbeeld van de /api/todoitems/{id} route getoond.

Follow the POST instructions to add another todo item, and then test the /api/todoitems route using Swagger.

Deze app maakt gebruik van een in-memory database. Als de app is gestopt en gestart, retourneert de voorgaande GET-aanvraag geen gegevens. If no data is returned, POST data to the app.

Routering en URL-paden

Het kenmerk [HttpGet] geeft een methode aan die reageert op een HTTP GET aanvraag. Het URL-pad voor elke methode wordt als volgt samengesteld:

  • Begin met de sjabloontekenreeks in het kenmerk Route van de controller:

    [Route("api/[controller]")]
    [ApiController]
    public class TodoItemsController : ControllerBase
    
  • Vervang [controller] door de naam van de controller. Dit is de naam van de controllerklasse minus het achtervoegsel 'Controller'. For this sample, the controller class name is TodoItemsController, so the controller name is "TodoItems". ASP.NET Core routing is case insensitive.

  • Als het kenmerk [HttpGet] een routesjabloon heeft (bijvoorbeeld [HttpGet("products")]), voegt u dit toe aan het pad. In dit voorbeeld wordt geen sjabloon gebruikt. Zie Kenmerkroutering met http[werkwoord]-kenmerken voor meer informatie.

In de volgende GetTodoItem-methode is "{id}" een placeholder voor de unieke identificatie van het item to-do. Wanneer GetTodoItem wordt aangeroepen, wordt de waarde van "{id}" in de URL verstrekt aan de methode in de parameter id.

[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return todoItem;
}

Return values

Het retourtype van de GetTodoItems en GetTodoItem methoden is ActionResult<T-type>. ASP.NET Core automatically serializes the object to JSON and writes the JSON into the body of the response message. The response code for this return type is 200 OK, assuming there are no unhandled exceptions. Niet-verwerkte uitzonderingen worden omgezet in 5xx-fouten.

ActionResult retourtypen kunnen een breed scala aan HTTP-statuscodes vertegenwoordigen. GetTodoItem kan bijvoorbeeld twee verschillende statuswaarden retourneren:

  • If no item matches the requested ID, the method returns a 404 statusNotFound error code.
  • Anders retourneert de methode 200 met een JSON-antwoordtekst. Het retourneren van item resulteert in een HTTP 200 antwoord.

De methode PutTodoItem

Bekijk de PutTodoItem methode:

[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
    if (id != todoItem.Id)
    {
        return BadRequest();
    }

    _context.Entry(todoItem).State = EntityState.Modified;

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!TodoItemExists(id))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return NoContent();
}

PutTodoItem is vergelijkbaar met PostTodoItem, met uitzondering van HTTP PUT. Het antwoord is 204 (geen inhoud). Volgens de HTTP-specificatie vereist een PUT aanvraag dat de client de volledige bijgewerkte entiteit verzendt, niet alleen de wijzigingen. To support partial updates, use HTTP PATCH.

De methode PutTodoItem testen

In dit voorbeeld wordt een in-memory database gebruikt die telkens wanneer de app wordt gestart, moet worden geïnitialiseerd. Er moet een item in de database staan voordat u een PUT-aanroep uitvoert. Roep GET aan om ervoor te zorgen dat er een item in de database staat voordat u een PUT-aanroep doet.

Gebruik de Swagger UI om de TodoItem met id = 1 bij te werken door de PUT-knop te gebruiken en stel de naam in op "feed fish". Let op: het antwoord is HTTP 204 No Content.

De methode DeleteTodoItem

Bekijk de DeleteTodoItem methode:

[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);
    if (todoItem == null)
    {
        return NotFound();
    }

    _context.TodoItems.Remove(todoItem);
    await _context.SaveChangesAsync();

    return NoContent();
}

De methode DeleteTodoItem testen

Gebruik de Swagger-gebruikersinterface om de TodoItem met Id = 1 te verwijderen. Let op: het antwoord is HTTP 204 No Content.

Testen met andere hulpprogramma's

Er zijn veel andere hulpprogramma's die kunnen worden gebruikt om web-API's te testen, bijvoorbeeld:

Zie voor meer informatie:

Prevent over-posting

Op dit moment wordt in de voorbeeld-app het hele TodoItem-object weergegeven. Productie-apps beperken doorgaans de gegevens die worden ingevoerd en geretourneerd met behulp van een subset van het model. Er zijn meerdere redenen achter dit, en beveiliging is een belangrijke. De subset van een model wordt meestal aangeduid als een DTO (Data Transfer Object), invoermodel of weergavemodel. DTO is used in this tutorial.

Een DTO kan worden gebruikt voor het volgende:

  • Prevent over-posting.
  • Eigenschappen verbergen die klanten niet zouden moeten zien.
  • Laat bepaalde eigenschappen weg om de nettolading te verkleinen.
  • Maak objectgrafieken plat die geneste objecten bevatten. Platgemaakte objectgrafieken kunnen handiger zijn voor clients.

Als u de DTO-benadering wilt demonstreren, werkt u de TodoItem klasse bij om een geheim veld op te nemen:

namespace TodoApi.Models
{
    public class TodoItem
    {
        public long Id { get; set; }
        public string? Name { get; set; }
        public bool IsComplete { get; set; }
        public string? Secret { get; set; }
    }
}

Het geheime veld moet worden verborgen voor deze app, maar een beheer-app kan ervoor kiezen om het beschikbaar te maken.

Controleer of u de geheime veldgegevens kunt plaatsen en ophalen.

Een DTO-model maken:

namespace TodoApi.Models;

public class TodoItemDTO
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

Werk de TodoItemsController bij om TodoItemDTOte gebruiken:

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

namespace TodoApi.Controllers;

[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
    private readonly TodoContext _context;

    public TodoItemsController(TodoContext context)
    {
        _context = context;
    }

    // GET: api/TodoItems
    [HttpGet]
    public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
    {
        return await _context.TodoItems
            .Select(x => ItemToDTO(x))
            .ToListAsync();
    }

    // GET: api/TodoItems/5
    // <snippet_GetByID>
    [HttpGet("{id}")]
    public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);

        if (todoItem == null)
        {
            return NotFound();
        }

        return ItemToDTO(todoItem);
    }
    // </snippet_GetByID>

    // PUT: api/TodoItems/5
    // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
    // <snippet_Update>
    [HttpPut("{id}")]
    public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
    {
        if (id != todoDTO.Id)
        {
            return BadRequest();
        }

        var todoItem = await _context.TodoItems.FindAsync(id);
        if (todoItem == null)
        {
            return NotFound();
        }

        todoItem.Name = todoDTO.Name;
        todoItem.IsComplete = todoDTO.IsComplete;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
        {
            return NotFound();
        }

        return NoContent();
    }
    // </snippet_Update>

    // POST: api/TodoItems
    // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
    // <snippet_Create>
    [HttpPost]
    public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
    {
        var todoItem = new TodoItem
        {
            IsComplete = todoDTO.IsComplete,
            Name = todoDTO.Name
        };

        _context.TodoItems.Add(todoItem);
        await _context.SaveChangesAsync();

        return CreatedAtAction(
            nameof(GetTodoItem),
            new { id = todoItem.Id },
            ItemToDTO(todoItem));
    }
    // </snippet_Create>

    // DELETE: api/TodoItems/5
    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);
        if (todoItem == null)
        {
            return NotFound();
        }

        _context.TodoItems.Remove(todoItem);
        await _context.SaveChangesAsync();

        return NoContent();
    }

    private bool TodoItemExists(long id)
    {
        return _context.TodoItems.Any(e => e.Id == id);
    }

    private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
       new TodoItemDTO
       {
           Id = todoItem.Id,
           Name = todoItem.Name,
           IsComplete = todoItem.IsComplete
       };
}

Controleer of u het geheime veld niet kunt posten of ophalen.

De web-API aanroepen met JavaScript

Zie zelfstudie: Een ASP.NET Core-web-API aanroepen met JavaScript.

Web-API-videoserie

Zie video: Beginnersreeks voor: Web-API's.

Patronen voor bedrijfsweb-apps

Zie Enterprise-web-apppatronen voor hulp bij het maken van een betrouwbare, veilige, performante, testbare en schaalbare ASP.NET Core-app. Er is een volledige voorbeeldweb-app van productiekwaliteit beschikbaar waarmee de patronen worden geïmplementeerd.

Verificatieondersteuning toevoegen aan een web-API

ASP.NET Core Identity voegt de aanmeldingsfunctionaliteit van de gebruikersinterface (UI) toe aan ASP.NET Core-web-apps. Gebruik een van de volgende manieren om web-API's en SPA's te beveiligen:

Duende Identity Server is een OpenID Connect- en OAuth 2.0-framework voor ASP.NET Core. Duende Identity Server maakt de volgende beveiligingsfuncties mogelijk:

  • Verificatie als een service (AaaS)
  • Eenmalige aanmelding/uit (SSO) voor meerdere toepassingstypen
  • Toegangsbeheer voor API's
  • Federation Gateway

Important

Duende Software might require you to pay a license fee for production use of Duende Identity Server. Zie Migreren van ASP.NET Core in .NET 5 naar .NET 6 voor meer informatie.

Zie de documentatie van Duende Server (Duende Identity Software-website) voor meer informatie.

Publiceren naar Azure

Zie quickstart: Een ASP.NET-web-app implementeren voor meer informatie over het implementeren in Azure.

Additional resources

Bekijk of download voorbeeldcode voor deze zelfstudie. Zie hoe te downloaden.

Zie de volgende bronnen voor meer informatie:

In deze zelfstudie leert u de basisbeginselen van het bouwen van een web-API op basis van een controller die gebruikmaakt van een database. Another approach to creating APIs in ASP.NET Core is to create minimal APIs. For help with choosing between minimal APIs and controller-based APIs, see APIs overview. Zie zelfstudie: Een minimale API maken met ASP.NET Core voor een zelfstudie over het maken van een minimale API.

Overview

In deze tutorial maak je de volgende API aan:

API Description Request body Response body
GET /api/todoitems Alle to-do items ophalen None Reeks van to-do items
GET /api/todoitems/{id} Een item ophalen met ID None To-do item
POST /api/todoitems Een nieuw item toevoegen To-do item To-do item
PUT /api/todoitems/{id} Een bestaand item bijwerken To-do item None
DELETE /api/todoitems/{id}     Een item verwijderen None None

In het volgende diagram ziet u het ontwerp van de app.

De client wordt vertegenwoordigd door een vak aan de linkerkant. Het verzendt een aanvraag en ontvangt een antwoord van de toepassing, een vak aan de rechterkant. In het toepassingsvak vertegenwoordigen drie vakken de controller, het model en de gegevenstoegangslaag. De aanvraag wordt geleverd in de controller van de toepassing en lees-/schrijfbewerkingen worden uitgevoerd tussen de controller en de gegevenstoegangslaag. Het model wordt geserialiseerd en geretourneerd naar de client in het antwoord.

Prerequisites

Een webproject maken

  • From the File menu, select New>Project.
  • Enter Web API in the search box.
  • Selecteer de ASP.NET Core Web API-sjabloon en selecteer Volgende.
  • Geef in het dialoogvenster Uw nieuwe project configureren de naam van het project TodoApi en selecteer Volgende.
  • In the Additional information dialog:
    • Confirm the Framework is .NET 8.0 (Long Term Support).
    • Controleer of het selectievakje voor Controllers gebruiken (schakel het selectievakje uit om minimale API's te gebruiken) is ingeschakeld.
    • Controleer of het selectievakje voor OpenAPI-ondersteuning inschakelen is ingeschakeld.
    • Select Create.

Een NuGet-pakket toevoegen

Er moet een NuGet-pakket worden toegevoegd ter ondersteuning van de database die in deze zelfstudie wordt gebruikt.

  • From the Tools menu, select NuGet Package Manager > Manage NuGet Packages for Solution.
  • Select the Browse tab.
  • Enter Microsoft.EntityFrameworkCore.InMemory in the search box, and then select Microsoft.EntityFrameworkCore.InMemory.
  • Select the Project checkbox in the right pane and then select Install.

Note

Zie de artikelen onder Pakketten installeren en beheren bij Pakketconsumptieworkflow (NuGet-documentatie) voor hulp bij het toevoegen van pakketten aan .NET-apps. Confirm correct package versions at NuGet.org.

Het project testen

The project template creates a WeatherForecast API with support for Swagger.

Druk op Ctrl+F5 om uit te voeren zonder het foutopsporingsprogramma.

Visual Studio geeft het volgende dialoogvenster weer wanneer een project nog niet is geconfigureerd voor het gebruik van SSL:

Dit project is geconfigureerd voor het gebruik van SSL. Als u SSL-waarschuwingen in de browser wilt voorkomen, kunt u ervoor kiezen om het zelfondertekende certificaat te vertrouwen dat IIS Express heeft gegenereerd. Wilt u het IIS Express SSL-certificaat vertrouwen?

Select Yes if you trust the IIS Express SSL certificate.

Het volgende dialoogvenster wordt weergegeven:

Dialoogvenster Beveiligingswaarschuwing

Select Yes if you agree to trust the development certificate.

Zie Firefox SEC_ERROR_INADEQUATE_KEY_USAGE certificaatfout voor meer informatie over het vertrouwen van de Firefox-browser.

Visual Studio start de standaardbrowser en gaat naar https://localhost:<port>/swagger/index.html, waarbij <port> een willekeurig gekozen poortnummer is dat is ingesteld bij het maken van het project.

De Swagger-pagina /swagger/index.html wordt weergegeven. Select GET>Try it out>Execute. Op de pagina wordt het volgende weergegeven:

  • The Curl command to test the WeatherForecast API.
  • De URL voor het testen van de WeatherForecast-API.
  • De antwoordcode, hoofdtekst en headers.
  • Een vervolgkeuzelijst met mediatypen en de voorbeeldwaarde en het schema.

Als de Swagger-pagina niet wordt weergegeven, raadpleegt u dit GitHub-probleem.

Swagger wordt gebruikt voor het genereren van nuttige documentatie en Help-pagina's voor web-API's. In deze zelfstudie wordt Swagger gebruikt om de app te testen. Zie ASP.NET Core-web-API-documentatie met Swagger/OpenAPI voor meer informatie over Swagger.

Copy and paste the Request URL in the browser: https://localhost:<port>/weatherforecast

JSON die vergelijkbaar is met het volgende voorbeeld wordt geretourneerd:

[
    {
        "date": "2019-07-16T19:04:05.7257911-06:00",
        "temperatureC": 52,
        "temperatureF": 125,
        "summary": "Mild"
    },
    {
        "date": "2019-07-17T19:04:05.7258461-06:00",
        "temperatureC": 36,
        "temperatureF": 96,
        "summary": "Warm"
    },
    {
        "date": "2019-07-18T19:04:05.7258467-06:00",
        "temperatureC": 39,
        "temperatureF": 102,
        "summary": "Cool"
    },
    {
        "date": "2019-07-19T19:04:05.7258471-06:00",
        "temperatureC": 10,
        "temperatureF": 49,
        "summary": "Bracing"
    },
    {
        "date": "2019-07-20T19:04:05.7258474-06:00",
        "temperatureC": -1,
        "temperatureF": 31,
        "summary": "Chilly"
    }
]

Een modelklasse toevoegen

A model is a set of classes that represent the data that the app manages. Het model voor deze app is de TodoItem klasse.

  • In Solution Explorer, right-click the project. Select Add>New Folder. Geef de map een naam Models.
  • Right-click the Models folder and select Add>Class. Name the class TodoItem and select Add.
  • Vervang de sjablooncode door het volgende:
namespace TodoApi.Models;

public class TodoItem
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

De eigenschap Id fungeert als de unieke sleutel in een relationele database.

Modelklassen kunnen overal in het project worden gebruikt, maar de map Models wordt standaard gebruikt.

Een databasecontext toevoegen

The database context is the main class that coordinates Entity Framework functionality for a data model. Deze klasse wordt gemaakt door te erven van de Microsoft.EntityFrameworkCore.DbContext klasse.

  • Right-click the Models folder and select Add>Class. Name the class TodoContext and click Add.
  • Voer de volgende code in:

    using Microsoft.EntityFrameworkCore;
    
    namespace TodoApi.Models;
    
    public class TodoContext : DbContext
    {
        public TodoContext(DbContextOptions<TodoContext> options)
            : base(options)
        {
        }
    
        public DbSet<TodoItem> TodoItems { get; set; } = null!;
    }
    

De databasecontext registreren

In ASP.NET Core moeten services zoals de DB-context worden geregistreerd bij de afhankelijkheidsinjectiecontainer (DI ). De container biedt de service aan controllers.

Werk Program.cs bij met de volgende gemarkeerde code:

using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddDbContext<TodoContext>(opt =>
    opt.UseInMemoryDatabase("TodoList"));
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

De voorgaande code:

  • Voegt using richtlijnen toe.
  • Voegt de databasecontext toe aan de DI-container.
  • Hiermee geeft u op dat de databasecontext een in-memory database gebruikt.

Genereer een controller

  • Klik met de rechtermuisknop op de map Controllers.

  • Select Add>New Scaffolded Item.

  • Selecteer API-controller met acties, met behulp van Entity Framework en selecteer vervolgens Toevoegen.

  • In het dialoogvenster API-controller toevoegen met acties, met behulp van Entity Framework:

    • Select TodoItem (TodoApi.Models) in the Model class.
    • Select TodoContext (TodoApi.Models) in the Data context class.
    • Select Add.

    If the scaffolding operation fails, select Add to try scaffolding a second time.

De gegenereerde code:

  • Markeert de klasse met het kenmerk [ApiController]. Dit kenmerk geeft aan dat de controller reageert op web-API-aanvragen. Zie Web-API's maken met ASP.NET Core voor informatie over specifiek gedrag dat het kenmerk inschakelt.
  • Maakt gebruik van DI om de databasecontext (TodoContext) in de controller te injecteren. The database context is used in each of the CRUD methods in the controller.

De ASP.NET Core-sjablonen voor:

  • Controllers met weergaven bevatten [action] in de routesjabloon.
  • API-controllers bevatten geen [action] in de routesjabloon.

When the [action] token isn't in the route template, the action name (method name) isn't included in the endpoint. Dat wil gezegd: de naam van de gekoppelde methode van de actie wordt niet gebruikt in de overeenkomende route.

De methode voor het aanmaken van PostTodoItem bijwerken

Update the return statement in the PostTodoItem to use the nameof operator:

[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
{
    _context.TodoItems.Add(todoItem);
    await _context.SaveChangesAsync();

    //    return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
    return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
}

De voorgaande code is een HTTP POST methode, zoals aangegeven door het kenmerk [HttpPost]. Met de methode wordt de waarde van de TodoItem opgehaald uit de hoofdtekst van de HTTP-aanvraag.

Zie Kenmerkroutering met http[werkwoord]-kenmerken voor meer informatie.

De methode CreatedAtAction:

  • Retourneert een HTTP 201-statuscode als dit lukt. HTTP 201 is het standaardantwoord voor een HTTP POST methode waarmee een nieuwe resource op de server wordt gemaakt.
  • Adds a Location header to the response. The Location header specifies the URI of the newly created to-do item. Zie 10.2.2 2 201 Gemaakt voor meer informatie.
  • Verwijst naar de GetTodoItem actie om de URI van de Location header te maken. Het trefwoord C# nameof wordt gebruikt om te voorkomen dat de actienaam in de CreatedAtAction aanroep hard wordt gecodeerd.

Test PostTodoItem

  • Druk op Ctrl+F5 om de app uit te voeren.

  • In the Swagger browser window, select POST /api/TodoItems, and then select Try it out.

  • In the Request body input window, update the JSON. For example,

    {
      "name": "walk dog",
      "isComplete": true
    }
    
  • Select Execute

    Swagger POST

De URI van de locatieheader testen

In the preceding POST, the Swagger UI shows the location header under Response headers. Bijvoorbeeld location: https://localhost:7260/api/TodoItems/1. De locatieheader toont de URI voor de gemaakte resource.

De locatiekoptekst testen:

  • In the Swagger browser window, select GET /api/TodoItems/{id}, and then select Try it out.

  • Enter 1 in the id input box, and then select Execute.

    Swagger GET

De GET-methoden onderzoeken

Er worden twee GET-eindpunten geïmplementeerd:

  • GET /api/todoitems
  • GET /api/todoitems/{id}

In de vorige sectie is een voorbeeld van de /api/todoitems/{id} route getoond.

Follow the POST instructions to add another todo item, and then test the /api/todoitems route using Swagger.

Deze app maakt gebruik van een in-memory database. Als de app is gestopt en gestart, retourneert de voorgaande GET-aanvraag geen gegevens. If no data is returned, POST data to the app.

Routering en URL-paden

Het kenmerk [HttpGet] geeft een methode aan die reageert op een HTTP GET aanvraag. Het URL-pad voor elke methode wordt als volgt samengesteld:

  • Begin met de sjabloontekenreeks in het kenmerk Route van de controller:

    [Route("api/[controller]")]
    [ApiController]
    public class TodoItemsController : ControllerBase
    
  • Vervang [controller] door de naam van de controller. Dit is de naam van de controllerklasse minus het achtervoegsel 'Controller'. For this sample, the controller class name is TodoItemsController, so the controller name is "TodoItems". ASP.NET Core routing is case insensitive.

  • Als het kenmerk [HttpGet] een routesjabloon heeft (bijvoorbeeld [HttpGet("products")]), voegt u dit toe aan het pad. In dit voorbeeld wordt geen sjabloon gebruikt. Zie Kenmerkroutering met http[werkwoord]-kenmerken voor meer informatie.

In de volgende GetTodoItem-methode is "{id}" een placeholder voor de unieke identificatie van het item to-do. Wanneer GetTodoItem wordt aangeroepen, wordt de waarde van "{id}" in de URL verstrekt aan de methode in de parameter id.

[HttpGet("{id}")]
public async Task<ActionResult<TodoItem>> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return todoItem;
}

Return values

Het retourtype van de GetTodoItems en GetTodoItem methoden is ActionResult<T-type>. ASP.NET Core automatically serializes the object to JSON and writes the JSON into the body of the response message. The response code for this return type is 200 OK, assuming there are no unhandled exceptions. Niet-verwerkte uitzonderingen worden omgezet in 5xx-fouten.

ActionResult retourtypen kunnen een breed scala aan HTTP-statuscodes vertegenwoordigen. GetTodoItem kan bijvoorbeeld twee verschillende statuswaarden retourneren:

  • If no item matches the requested ID, the method returns a 404 statusNotFound error code.
  • Anders retourneert de methode 200 met een JSON-antwoordtekst. Het retourneren van item resulteert in een HTTP 200 antwoord.

De methode PutTodoItem

Bekijk de PutTodoItem methode:

[HttpPut("{id}")]
public async Task<IActionResult> PutTodoItem(long id, TodoItem todoItem)
{
    if (id != todoItem.Id)
    {
        return BadRequest();
    }

    _context.Entry(todoItem).State = EntityState.Modified;

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        if (!TodoItemExists(id))
        {
            return NotFound();
        }
        else
        {
            throw;
        }
    }

    return NoContent();
}

PutTodoItem is vergelijkbaar met PostTodoItem, met uitzondering van HTTP PUT. Het antwoord is 204 (geen inhoud). Volgens de HTTP-specificatie vereist een PUT aanvraag dat de client de volledige bijgewerkte entiteit verzendt, niet alleen de wijzigingen. To support partial updates, use HTTP PATCH.

De methode PutTodoItem testen

In dit voorbeeld wordt een in-memory database gebruikt die telkens wanneer de app wordt gestart, moet worden geïnitialiseerd. Er moet een item in de database staan voordat u een PUT-aanroep uitvoert. Roep GET aan om ervoor te zorgen dat er een item in de database staat voordat u een PUT-aanroep doet.

Gebruik de Swagger UI om de TodoItem met id = 1 bij te werken door de PUT-knop te gebruiken en stel de naam in op "feed fish". Let op: het antwoord is HTTP 204 No Content.

De methode DeleteTodoItem

Bekijk de DeleteTodoItem methode:

[HttpDelete("{id}")]
public async Task<IActionResult> DeleteTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);
    if (todoItem == null)
    {
        return NotFound();
    }

    _context.TodoItems.Remove(todoItem);
    await _context.SaveChangesAsync();

    return NoContent();
}

De methode DeleteTodoItem testen

Gebruik de Swagger-gebruikersinterface om de TodoItem met Id = 1 te verwijderen. Let op: het antwoord is HTTP 204 No Content.

Testen met andere hulpprogramma's

Er zijn veel andere hulpprogramma's die kunnen worden gebruikt om web-API's te testen, bijvoorbeeld:

Zie voor meer informatie:

Prevent over-posting

Op dit moment wordt in de voorbeeld-app het hele TodoItem-object weergegeven. Productie-apps beperken doorgaans de gegevens die worden ingevoerd en geretourneerd met behulp van een subset van het model. Er zijn meerdere redenen achter dit, en beveiliging is een belangrijke. De subset van een model wordt meestal aangeduid als een DTO (Data Transfer Object), invoermodel of weergavemodel. DTO is used in this tutorial.

Een DTO kan worden gebruikt voor het volgende:

  • Prevent over-posting.
  • Eigenschappen verbergen die klanten niet zouden moeten zien.
  • Laat bepaalde eigenschappen weg om de nettolading te verkleinen.
  • Maak objectgrafieken plat die geneste objecten bevatten. Platgemaakte objectgrafieken kunnen handiger zijn voor clients.

Als u de DTO-benadering wilt demonstreren, werkt u de TodoItem klasse bij om een geheim veld op te nemen:

namespace TodoApi.Models
{
    public class TodoItem
    {
        public long Id { get; set; }
        public string? Name { get; set; }
        public bool IsComplete { get; set; }
        public string? Secret { get; set; }
    }
}

Het geheime veld moet worden verborgen voor deze app, maar een beheer-app kan ervoor kiezen om het beschikbaar te maken.

Controleer of u de geheime veldgegevens kunt plaatsen en ophalen.

Een DTO-model maken:

namespace TodoApi.Models;

public class TodoItemDTO
{
    public long Id { get; set; }
    public string? Name { get; set; }
    public bool IsComplete { get; set; }
}

Werk de TodoItemsController bij om TodoItemDTOte gebruiken:

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using TodoApi.Models;

namespace TodoApi.Controllers;

[Route("api/[controller]")]
[ApiController]
public class TodoItemsController : ControllerBase
{
    private readonly TodoContext _context;

    public TodoItemsController(TodoContext context)
    {
        _context = context;
    }

    // GET: api/TodoItems
    [HttpGet]
    public async Task<ActionResult<IEnumerable<TodoItemDTO>>> GetTodoItems()
    {
        return await _context.TodoItems
            .Select(x => ItemToDTO(x))
            .ToListAsync();
    }

    // GET: api/TodoItems/5
    // <snippet_GetByID>
    [HttpGet("{id}")]
    public async Task<ActionResult<TodoItemDTO>> GetTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);

        if (todoItem == null)
        {
            return NotFound();
        }

        return ItemToDTO(todoItem);
    }
    // </snippet_GetByID>

    // PUT: api/TodoItems/5
    // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
    // <snippet_Update>
    [HttpPut("{id}")]
    public async Task<IActionResult> PutTodoItem(long id, TodoItemDTO todoDTO)
    {
        if (id != todoDTO.Id)
        {
            return BadRequest();
        }

        var todoItem = await _context.TodoItems.FindAsync(id);
        if (todoItem == null)
        {
            return NotFound();
        }

        todoItem.Name = todoDTO.Name;
        todoItem.IsComplete = todoDTO.IsComplete;

        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException) when (!TodoItemExists(id))
        {
            return NotFound();
        }

        return NoContent();
    }
    // </snippet_Update>

    // POST: api/TodoItems
    // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754
    // <snippet_Create>
    [HttpPost]
    public async Task<ActionResult<TodoItemDTO>> PostTodoItem(TodoItemDTO todoDTO)
    {
        var todoItem = new TodoItem
        {
            IsComplete = todoDTO.IsComplete,
            Name = todoDTO.Name
        };

        _context.TodoItems.Add(todoItem);
        await _context.SaveChangesAsync();

        return CreatedAtAction(
            nameof(GetTodoItem),
            new { id = todoItem.Id },
            ItemToDTO(todoItem));
    }
    // </snippet_Create>

    // DELETE: api/TodoItems/5
    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteTodoItem(long id)
    {
        var todoItem = await _context.TodoItems.FindAsync(id);
        if (todoItem == null)
        {
            return NotFound();
        }

        _context.TodoItems.Remove(todoItem);
        await _context.SaveChangesAsync();

        return NoContent();
    }

    private bool TodoItemExists(long id)
    {
        return _context.TodoItems.Any(e => e.Id == id);
    }

    private static TodoItemDTO ItemToDTO(TodoItem todoItem) =>
       new TodoItemDTO
       {
           Id = todoItem.Id,
           Name = todoItem.Name,
           IsComplete = todoItem.IsComplete
       };
}

Controleer of u het geheime veld niet kunt posten of ophalen.

De web-API aanroepen met JavaScript

Zie zelfstudie: Een ASP.NET Core-web-API aanroepen met JavaScript.

Web-API-videoserie

Zie video: Beginnersreeks voor: Web-API's.

Patronen voor bedrijfsweb-apps

Zie Enterprise-web-apppatronen voor hulp bij het maken van een betrouwbare, veilige, performante, testbare en schaalbare ASP.NET Core-app. Er is een volledige voorbeeldweb-app van productiekwaliteit beschikbaar waarmee de patronen worden geïmplementeerd.

Verificatieondersteuning toevoegen aan een web-API

ASP.NET Core Identity voegt de aanmeldingsfunctionaliteit van de gebruikersinterface (UI) toe aan ASP.NET Core-web-apps. Gebruik een van de volgende manieren om web-API's en SPA's te beveiligen:

Duende Identity Server is een OpenID Connect- en OAuth 2.0-framework voor ASP.NET Core. Duende Identity Server maakt de volgende beveiligingsfuncties mogelijk:

  • Verificatie als een service (AaaS)
  • Eenmalige aanmelding/uit (SSO) voor meerdere toepassingstypen
  • Toegangsbeheer voor API's
  • Federation Gateway

Important

Duende Software might require you to pay a license fee for production use of Duende Identity Server. Zie Migreren van ASP.NET Core in .NET 5 naar .NET 6 voor meer informatie.

Zie de documentatie van Duende Server (Duende Identity Software-website) voor meer informatie.

Publiceren naar Azure

Zie quickstart: Een ASP.NET-web-app implementeren voor meer informatie over het implementeren in Azure.

Additional resources

Bekijk of download voorbeeldcode voor deze zelfstudie. Zie hoe te downloaden.

Zie de volgende bronnen voor meer informatie: