Dela via


Självstudie: Skapa ett kontrollantbaserat webb-API med ASP.NET Core

Not

Det här är inte den senaste versionen av den här artikeln. För den nuvarande utgåvan, se den .NET 9-versionen av den här artikeln.

Varning

Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i .NET och .NET Core Support Policy. För den nuvarande utgåvan, se den .NET 9-versionen av den här artikeln.

Viktig

Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps kommersiellt. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, med avseende på den information som tillhandahålls här.

För den nuvarande utgåvan, se den .NET 9-versionen av den här artikeln.

Av Tim Deschryver och Rick Anderson

I den här självstudien lär du dig grunderna i att skapa ett kontrollantbaserat webb-API som använder en databas. En annan metod för att skapa API:er i ASP.NET Core är att skapa minimala API:er. Hjälp med att välja mellan minimala API:er och kontrollantbaserade API:er finns i översikten över API:er. En självstudiekurs om hur du skapar ett minimalt API finns i Självstudie: Skapa ett minimalt API med ASP.NET Core.

Överblick

I den här handledningen skapas följande API:

API Beskrivning Begäransinnehåll Svarskropp
GET /api/todoitems Hämta alla to-do objekt Ingen Matris med to-do objekt
GET /api/todoitems/{id} Hämta ett objekt efter ID Ingen Att göra-objekt
POST /api/todoitems Lägga till ett nytt objekt Att göra-objekt Att göra-objekt
PUT /api/todoitems/{id} Uppdatera ett befintligt objekt Att göra-objekt Ingen
DELETE /api/todoitems/{id}     Ta bort ett objekt Ingen Ingen

Följande diagram visar appens design.

Klienten representeras av en ruta till vänster. Den skickar en begäran och får ett svar från programmet, en ruta som ritats till höger. I programrutan representerar tre rutor kontrollanten, modellen och dataåtkomstskiktet. Begäran kommer till programmets kontrollant och läs-/skrivåtgärder sker mellan kontrollanten och dataåtkomstlagret. Modellen serialiseras och returneras till klienten i svaret.

Förutsättningar

Skapa ett webb-API-projekt

  • På menyn Arkiv väljer du Nytt>Projekt.
  • Ange Web-API i sökrutan.
  • Välj mallen ASP.NET Core Web API och välj Nästa.
  • I dialogrutan Konfigurera det nya projektetnamnger du projektet TodoApi och väljer Nästa.
  • I dialogrutan Ytterligare information:
    • Bekräfta att Framework är .NET 9.0 (Standardtermstöd).
    • Bekräfta att kryssrutan för Aktivera OpenAPI-stöd är markerad.
    • Bekräfta kryssrutan för Använd kontrollanter (avmarkera om du vill använda minimala API:er) är markerad.
    • Välj Skapa.

Lägga till ett NuGet-paket

Ett NuGet-paket måste läggas till för att stödja databasen som används i den här guiden.

  • På menyn Verktyg väljer du NuGet Package Manager > Manage NuGet Packages for Solution.
  • Välj fliken Bläddra.
  • Ange Microsoft.EntityFrameworkCore.InMemory i sökrutan och välj sedan Microsoft.EntityFrameworkCore.InMemory.
  • Markera kryssrutan Project i panelen till höger och välj sedan Install.

Not

Mer information om hur du lägger till paket i .NET-appar finns i artiklarna under Installera och hantera paketArbetsflöde för paketförbrukning (NuGet-dokumentation). Bekräfta rätt paketversioner på NuGet.org.

Kör projektet

Projektmallen skapar ett WeatherForecast API med stöd för OpenAPI-.

Tryck på Ctrl+F5 för att köra utan felsökningsprogrammet.

Visual Studio visar följande dialogruta när ett projekt ännu inte har konfigurerats för att använda SSL:

Det här projektet är konfigurerat att använda SSL. För att undvika SSL-varningar i webbläsaren kan du välja att lita på det självsignerade certifikat som IIS Express har genererat. Vill du lita på IIS Express SSL-certifikatet?

Välj Ja om du litar på IIS Express SSL-certifikatet.

Följande dialogruta visas:

säkerhetsvarningsdialog

Välj Ja om du samtycker till att lita på utvecklingscertifikatet.

Information om hur du kan lita på webbläsaren Firefox finns i Firefox SEC_ERROR_INADEQUATE_KEY_USAGE certifikatfel.

Visual Studio startar ett terminalfönster och visar URL:en för appen som körs. API:et finns på https://localhost:<port>, där <port> är ett slumpmässigt valt portnummer som anges när projektet skapas.

...
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+klicka på den HTTPS-URL som finns i utgångsdatan för att testa webbappen i en webbläsare. Det finns ingen slutpunkt på https://localhost:<port>, så webbläsaren returnerar HTTP 404 Hittades inte.

Lägg till /weatherforecast till URL:en för att testa WeatherForecast-API:et. Webbläsaren visar JSON som liknar följande exempel:

[
    {
        "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"
    }
]

Testa projektet

I den här handledningen används Endpoints Explorer och .http-filer för att testa API:t.

Lägga till en modellklass

En modell är en uppsättning klasser som representerar de data som appen hanterar. Modellen för den här appen är klassen TodoItem.

  • Högerklicka på projektet i Solution Explorer. Välj Lägg till>ny mapp. Ge mappen namnet Models.
  • Högerklicka på mappen Models och välj Lägg till>klass. Ge klassen namnet TodoItem och välj Lägg till.
  • Ersätt mallkoden med följande:
namespace TodoApi.Models;

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

Egenskapen Id fungerar som den unika nyckeln i en relationsdatabas.

Modellklasser kan placeras var som helst i projektet, men mappen Models används enligt konvention.

Lägga till en databaskontext

Den databaskontexten är huvudklassen som samordnar Entity Framework-funktioner för en datamodell. Den här klassen skapas genom att härledas från klassen Microsoft.EntityFrameworkCore.DbContext.

  • Högerklicka på mappen Models och välj Lägg till>klass. Ge klassen namnet TodoContext och klicka på Lägg till.

  • Ange följande kod:

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

Registrera databaskontexten

I ASP.NET Core måste tjänster som DB-kontexten registreras i beroendeinjektion (DI)-containern. Containern tillhandahåller tjänsten till kontrollanter.

Uppdatera Program.cs med följande markerade kod:

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();

Föregående kod:

  • Lägger till using direktiv.
  • Lägger till databaskontexten i DI-containern.
  • Anger att databaskontexten ska använda en minnesintern databas.

Generera en styrenhet

  • Högerklicka på mappen Controllers.

  • Välj Lägg till>New Scaffolded Item.

  • Välj API-kontrollant med åtgärder, använd Entity Frameworkoch välj sedan Lägg till.

  • I dialogrutan Lägg till API-kontroller med åtgärder, använd Entity Framework:

    • Välj TodoItem (TodoApi.Models) i klassen Model.
    • Välj TodoContext (TodoApi.Models) i den datakontextklassen .
    • Välj Lägg till.

    Om scaffolding-åtgärden misslyckas väljer du Lägg till för att prova scaffolding igen.

Det här steget lägger till Microsoft.VisualStudio.Web.CodeGeneration.Design- och Microsoft.EntityFrameworkCore.Tools NuGet-paket i projektet. Dessa paket krävs för ramverk.

Den genererade koden:

  • Markerar klassen med attributet [ApiController]. Det här attributet anger att kontrollanten svarar på webb-API-begäranden. Information om specifika beteenden som attributet aktiverar finns i Skapa webb-API:er med ASP.NET Core.
  • Använder DI för att mata in databaskontexten (TodoContext) i kontrollanten. Databaskontexten används i var och en av de CRUD- metoderna i kontrollanten.

ASP.NET Core-mallarna för:

  • Kontrollanter med vyer innehåller [action] i routningsmallen.
  • API-kontrollanter inkluderar inte [action] i routningsmallen.

När [action] token inte finns i routningsmallen inkluderas inte -åtgärden namn (metodnamn) i slutpunkten. Åtgärdens associerade metodnamn används alltså inte i matchande väg.

Uppdatera metoden PostTodoItem create

Uppdatera retursatsen i PostTodoItem för att använda nameof operatorn:

[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);
}

Föregående kod är en HTTP POST metod, vilket anges av attributet [HttpPost]. Metoden hämtar värdet för TodoItem från brödtexten i HTTP-begäran.

För mer information, se Attributdirigering med Http[Verb]-attribut.

Metoden CreatedAtAction:

  • Returnerar en HTTP 201-statuskod om den lyckas. HTTP 201 är standardsvaret för en HTTP POST-metod som skapar en ny resurs på servern.
  • Lägger till en Location-rubrik i svaret. Location-huvudet anger URI- för det nyligen skapade to-do objektet. Mer information finns i 10.2.2 201 Skapad.
  • Refererar till åtgärden GetTodoItem för att skapa Location-huvudets URI. Nyckelordet C# nameof används för att undvika hårdkodning av åtgärdsnamnet i CreatedAtAction-anropet.

Test PostTodoItem

  • Välj Visa>Andra Fönster>Slutpunkter Utforskare.

  • Högerklicka på slutpunkten POST och välj Generera begäran.

    Snabbmenyn Endpoints Explorer med markerat menyalternativ

    En ny fil skapas i projektmappen med namnet TodoApi.http, med innehåll som liknar följande exempel:

    @TodoApi_HostAddress = https://localhost:49738
    
    POST {{TodoApi_HostAddress}}/api/todoitems
    Content-Type: application/json
    
    {
      //TodoItem
    }
    
    ###
    
    • Den första raden skapar en variabel som används för alla slutpunkter.
    • Nästa rad definierar en POST-begäran.
    • Raderna efter POST-begäranderaden definierar rubrikerna och en platshållare för begärandetexten.
    • Trippelhashtag-raden (###) är en begäranavgränsare: vad som följer efter är för en annan begäran.
  • POST-begäran förväntar sig en TodoItem. För att definiera todo, ersätt //TodoItem-kommentaren med följande JSON:

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

    Filen TodoApi.http bör nu se ut som i följande exempel, men med portnumret:

    @TodoApi_HostAddress = https://localhost:7260
    
    Post {{TodoApi_HostAddress}}/api/todoitems
    Content-Type: application/json
    
    {
      "name": "walk dog",
      "isComplete": true
    }
    
    ###
    
  • Kör appen.

  • Välj länken Skicka begäran som ligger ovanför POST begäranderaden.

    .http-filfönster med startlänken markerad.

    POST-begäran skickas till appen och svaret visas i fönstret Svar.

    .http-filfönstret med svar från POST-begäran.

Testa platsrubrikens URI

Testa appen genom att anropa GET slutpunkter från en webbläsare eller med hjälp av Endpoints Explorer. Följande steg gäller för Endpoints Explorer.

  • I Endpoints Explorerhögerklickar du på den första GET-slutpunkten och väljer Generera begäran.

    Följande innehåll läggs till i filen TodoApi.http:

    GET {{TodoApi_HostAddress}}/api/todoitems
    
    ###
    
  • Välj länken Skicka begäran som ligger ovanför den nya GET begäranderaden.

    GET-begäran skickas till appen och svaret visas i fönstret Svar.

  • Svarstexten liknar följande JSON:

    [
      {
        "id": 1,
        "name": "walk dog",
        "isComplete": true
      }
    ]
    
  • I Endpoints Explorerhögerklickar du på slutpunkten /api/todoitems/{id}GET och väljer Generera begäran. Följande innehåll läggs till i filen TodoApi.http:

    @id=0
    GET {{TodoApi_HostAddress}}/api/todoitems/{{id}}
    
    ###
    
  • Tilldela {@id} till 1 (i stället för 0).

  • Välj länken Skicka begäran som ligger ovanför den nya GET-begäranderaden.

    GET-begäran skickas till appen och svaret visas i fönstret Svar.

  • Svarstexten liknar följande JSON:

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

Granska GET-metoderna

Två GET-slutpunkter implementeras:

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

Föregående avsnitt visade ett exempel på vägen /api/todoitems/{id}.

Följ anvisningarna i POST för att lägga till en annan att-göra-post och testa sedan /api/todoitems vägen med hjälp av Swagger.

Den här appen använder en minnesintern databas. Om appen stoppas och startas returnerar inte den föregående GET-begäran några data. Om ingen data returneras, ska POST data till appen.

Routnings- och URL-sökvägar

Attributet [HttpGet] anger en metod som svarar på en HTTP GET begäran. URL-sökvägen för varje metod konstrueras på följande sätt:

  • Börja med mallsträngen i kontrollantens Route-attribut:

    [Route("api/[controller]")]
    [ApiController]
    public class TodoItemsController : ControllerBase
    
  • Ersätt [controller] med namnet på kontrollanten, som enligt konventionen är kontrollantens klassnamn minus suffixet "Controller". I det här exemplet är kontrollantklassnamnet TodoItemsController, så kontrollantnamnet är "TodoItems". ASP.NET Core routning är skiftlägesokänsligt.

  • Om attributet [HttpGet] har en routningsmall (till exempel [HttpGet("products")]) lägger du till den i sökvägen. Det här exemplet använder ingen mall. För mer information, se Attributdirigering med Http[Verb]-attribut.

I följande GetTodoItem-metod är "{id}" en platshållarvariabel för den unika identifieraren för det to-do objektet. När GetTodoItem anropas anges värdet för "{id}" i URL:en till metoden i parametern 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;
}

Returnera värden

Returtypen för metoderna GetTodoItems och GetTodoItem är ActionResult<T> typ. ASP.NET Core serialiserar automatiskt objektet till JSON- och skriver JSON i brödtexten i svarsmeddelandet. Svarskoden för den här returtypen är 200 OK, förutsatt att det inte finns några ohanterade undantag. Ohanterade undantag översätts till 5xx-fel.

ActionResult returtyper kan representera ett brett utbud av HTTP-statuskoder. Till exempel kan GetTodoItem returnera två olika statusvärden:

  • Om inget objekt matchar det begärda ID:t returnerar metoden en 404-statusNotFound felkod.
  • Annars returnerar metoden 200 med en JSON-svarstext. Om du returnerar item resulterar det i ett HTTP 200 svar.

PutTodoItem-metoden

Granska metoden PutTodoItem:

[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 liknar PostTodoItem, förutom att den använder HTTP PUT. Svaret är 204 (inget innehåll). Enligt HTTP-specifikationen kräver en PUT begäran att klienten skickar hela den uppdaterade entiteten, inte bara ändringarna. Om du vill ha stöd för partiella uppdateringar använder du HTTP PATCH-.

Testa metoden PutTodoItem

Det här exemplet använder en minnesintern databas som måste initieras varje gång appen startas. Det måste finnas ett objekt i databasen innan du gör ett PUT-anrop. Anropa GET för att se till att det finns ett objekt i databasen innan du gör ett PUT-anrop.

Använd metoden PUT för att uppdatera TodoItem som har ID = 1 och ange dess namn till "feed fish". Observera att svaret är HTTP 204 No Content.

  • I Endpoints Explorerhögerklickar du på slutpunkten PUT och väljer Generera begäran.

    Följande innehåll läggs till i filen TodoApi.http:

    PUT {{TodoApi_HostAddress}}/api/todoitems/{{id}}
    Content-Type: application/json
    
    {
      //TodoItem
    }
    
    ###
    
  • Ersätt {{id}} med 1på PUT-begäranderaden.

  • Ersätt platshållaren //TodoItem med följande rader:

    PUT {{TodoApi_HostAddress}}/api/todoitems/1
    Content-Type: application/json
    
    {
      "id": 1,
      "name": "feed fish",
      "isComplete": false
    }
    
  • Välj länken Skicka begäran som ligger ovanför den nya PUT-begäranderaden.

    PUT-begäran skickas till appen och svaret visas i fönstret Svar. Svarstexten är tom och statuskoden är 204.

Metoden DeleteTodoItem

Granska metoden DeleteTodoItem:

[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();
}

Testa metoden DeleteTodoItem

Använd metoden DELETE för att ta bort TodoItem som har ID = 1. Observera att svaret är HTTP 204 No Content.

  • I Endpoints Explorerhögerklickar du på slutpunkten DELETE och väljer Generera begäran.

    En DELETE-begäran läggs till i TodoApi.http.

  • Byt ut {{id}} i raden för DELETE-begäran mot 1. DELETE-begäran bör se ut som i följande exempel:

    DELETE {{TodoApi_HostAddress}}/api/todoitems/{{id}}
    
    ###
    
  • Välj länken Skicka begäran för DELETE-begäran.

    DELETE-begäran skickas till appen och svaret visas i fönstret Svar. Svarstexten är tom och statuskoden är 204.

Testa med andra verktyg

Det finns många andra verktyg som kan användas för att testa webb-API:er, till exempel:

Mer information finns i:

Förhindra överpublicering

För närvarande exponerar exempelappen hela TodoItem objektet. Produktionsappar begränsar vanligtvis de data som matas in och returneras med hjälp av en delmängd av modellen. Det finns flera orsaker till detta, och säkerheten är viktig. Delmängden av en modell kallas vanligtvis för ett dataöverföringsobjekt (DTO), indatamodell eller vymodell. DTO- används i den här handledningen.

En DTO kan användas för att:

  • Förhindra överpublicering.
  • Dölj egenskaper som klienter inte ska visa.
  • Utelämna vissa egenskaper för att minska nyttolaststorleken.
  • Platta ut objektdiagram som innehåller kapslade objekt. Utplattade objektdiagram kan vara enklare för klienter.

Om du vill demonstrera DTO-metoden uppdaterar du klassen TodoItem så att den innehåller ett hemligt fält:

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; }
}

Det hemliga fältet måste vara dolt från den här appen, men en administrativ app kan välja att exponera det.

Kontrollera att du kan skicka och hämta det hemliga fältet.

Skapa en DTO-modell i en Models/TodoItemsDTO.cs-fil.

namespace TodoApi.Models;

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

Uppdatera TodoItemsController för att använda TodoItemDTO:

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
       };
}

Kontrollera att du inte kan publicera eller hämta det hemliga fältet.

Anropa webb-API:et med JavaScript

Se Självstudie: Anropa ett ASP.NET Core-webb-API med JavaScript.

Videoserie för webb-API

Se Video om: Ny serie för nybörjare om web API:er.

Mönster för företagswebbappar

Vägledning om hur du skapar en tillförlitlig, säker, högpresterande, testbar och skalbar ASP.NET Core-app finns i Enterprise-webbappmönster. En komplett exempelwebbapp av produktionskvalitet som implementerar mönstren är tillgänglig.

Lägga till autentiseringsstöd i ett webb-API

ASP.NET Core Identity lägger till inloggningsfunktioner för användargränssnitt (UI) i ASP.NET Core-webbappar. Om du vill skydda webb-API:er och SPA:er använder du något av följande:

Duende Identity Server är ett OpenID Connect- och OAuth 2.0-ramverk för ASP.NET Core. Duende Identity Server aktiverar följande säkerhetsfunktioner:

  • Autentisering som en tjänst (AaaS)
  • Enkel inloggning/av(SSO) över flera programtyper
  • Åtkomstkontroll för API:er
  • Federation Gateway

Viktig

Duende Software kan kräva att du betalar en licensavgift för produktionsanvändning av Duende Identity Server. Mer information finns i Migrera från ASP.NET Core 5.0 till 6.0.

Mer information finns i Duende Identity Server-dokumentationen (Duende Software-webbplatsen).

Publicera till Azure

Information om hur du distribuerar till Azure finns i Snabbstart: Distribuera en ASP.NET webbapp.

Ytterligare resurser

Visa eller ladda ner exempelkod för den här handledningen. Se hur du laddar ned.

Mer information finns i följande resurser:

I den här självstudien lär du dig grunderna i att skapa ett kontrollantbaserat webb-API som använder en databas. En annan metod för att skapa API:er i ASP.NET Core är att skapa minimala API:er. Hjälp med att välja mellan minimala API:er och kontrollantbaserade API:er finns i översikten över API:er. En självstudiekurs om hur du skapar ett minimalt API finns i Självstudie: Skapa ett minimalt API med ASP.NET Core.

Överblick

I den här handledningen skapas följande API:

API Beskrivning Begärandetext Svarskropp
GET /api/todoitems Hämta alla to-do objekt Ingen Matris med to-do objekt
GET /api/todoitems/{id} Hämta ett objekt efter ID Ingen Att göra-objekt
POST /api/todoitems Lägga till ett nytt objekt Att göra-objekt Att göra-objekt
PUT /api/todoitems/{id} Uppdatera ett befintligt objekt Att göra-objekt Ingen
DELETE /api/todoitems/{id}     Ta bort ett objekt Ingen Ingen

Följande diagram visar appens design.

Klienten representeras av en ruta till vänster. Den skickar en begäran och får ett svar från programmet, en ruta som ritats till höger. I programrutan representerar tre rutor kontrollanten, modellen och dataåtkomstskiktet. Begäran kommer till programmets kontrollant och läs-/skrivåtgärder sker mellan kontrollanten och dataåtkomstlagret. Modellen serialiseras och returneras till klienten i svaret.

Förutsättningar

Skapa ett webbprojekt

  • På menyn Arkiv väljer du Nytt>Projekt.
  • Ange Web-API i sökrutan.
  • Välj mallen ASP.NET Core Web API och välj Nästa.
  • I dialogrutan Konfigurera det nya projektetnamnger du projektet TodoApi och väljer Nästa.
  • I dialogrutan Ytterligare information:
    • Bekräfta att Framework är .NET 8.0 (support på lång sikt).
    • Bekräfta kryssrutan för Använd kontrollanter (avmarkera om du vill använda minimala API:er) är markerad.
    • Bekräfta att kryssrutan för Aktivera OpenAPI-stöd är markerad.
    • Välj Skapa.

Lägga till ett NuGet-paket

Ett NuGet-paket måste läggas till för att stödja databasen som används i den här guiden.

  • På menyn Verktyg väljer du NuGet Package Manager > Manage NuGet Packages for Solution.
  • Välj fliken Bläddra.
  • Ange Microsoft.EntityFrameworkCore.InMemory i sökrutan och välj sedan Microsoft.EntityFrameworkCore.InMemory.
  • Markera kryssrutan Project i panelen till höger och välj sedan Install.

Notera

Mer information om hur du lägger till paket i .NET-appar finns i artiklarna under Installera och hantera paketArbetsflöde för paketförbrukning (NuGet-dokumentation). Bekräfta rätt paketversioner på NuGet.org.

Testa projektet

Projektmallen skapar ett WeatherForecast API med stöd för Swagger.

Tryck på Ctrl+F5 för att köra utan felsökningsprogrammet.

Visual Studio visar följande dialogruta när ett projekt ännu inte har konfigurerats för att använda SSL:

Det här projektet är konfigurerat att använda SSL. För att undvika SSL-varningar i webbläsaren kan du välja att lita på det självsignerade certifikat som IIS Express har genererat. Vill du lita på IIS Express SSL-certifikatet?

Välj Ja om du litar på IIS Express SSL-certifikatet.

Följande dialogruta visas:

säkerhetsvarningsdialog

Välj Ja om du samtycker till att lita på utvecklingscertifikatet.

Information om hur du kan lita på webbläsaren Firefox finns i Firefox SEC_ERROR_INADEQUATE_KEY_USAGE certifikatfel.

Visual Studio startar standardwebbläsaren och navigerar till https://localhost:<port>/swagger/index.html, där <port> är ett slumpmässigt valt portnummer som anges när projektet skapas.

Swagger-sida /swagger/index.html visas. Välj GET>Prova>Kör. Sidan visar:

  • Kommandot Curl för att testa WeatherForecast-API:et.
  • URL:en för att testa WeatherForecast-API:et.
  • Svarskoden, brödtexten och rubrikerna.
  • En listruta med medietyper och exempelvärdet och schemat.

Om Swagger-sidan inte visas kan du läsa detta GitHub-ärende.

Swagger används för att generera användbar dokumentation och hjälpsidor för webb-API:er. I den här handledningen används Swagger för att testa appen. Mer information om Swagger finns i ASP.NET Core web API-dokumentation med Swagger/OpenAPI.

Kopiera och klistra in url:en för begäran i webbläsaren: https://localhost:<port>/weatherforecast

JSON som liknar följande exempel returneras:

[
    {
        "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"
    }
]

Lägga till en modellklass

En modell är en uppsättning klasser som representerar de data som appen hanterar. Modellen för den här appen är klassen TodoItem.

  • Högerklicka på projektet i Solution Explorer. Välj Lägg till>ny mapp. Ge mappen namnet Models.
  • Högerklicka på mappen Models och välj Lägg till>klass. Ge klassen namnet TodoItem och välj Lägg till.
  • Ersätt mallkoden med följande:
namespace TodoApi.Models;

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

Egenskapen Id fungerar som den unika nyckeln i en relationsdatabas.

Modellklasser kan placeras var som helst i projektet, men mappen Models används enligt konvention.

Lägga till en databaskontext

Den databaskontexten är huvudklassen som samordnar Entity Framework-funktioner för en datamodell. Den här klassen skapas genom att härledas från klassen Microsoft.EntityFrameworkCore.DbContext.

  • Högerklicka på mappen Models och välj Lägg till>klass. Ge klassen namnet TodoContext och klicka på Lägg till.
  • Ange följande kod:

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

Registrera databaskontexten

I ASP.NET Core måste tjänster som DB-kontexten registreras i beroendeinjektion (DI)-containern. Containern tillhandahåller tjänsten till kontrollanter.

Uppdatera Program.cs med följande markerade kod:

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();

Föregående kod:

  • Lägger till using direktiv.
  • Lägger till databaskontexten i DI-containern.
  • Anger att databaskontexten ska använda en minnesintern databas.

Generera en styrenhet

  • Högerklicka på mappen Controllers.

  • Välj Lägg till>New Scaffolded Item.

  • Välj API-kontrollant med åtgärder, använd Entity Frameworkoch välj sedan Lägg till.

  • I dialogrutan Lägg till API-kontroller med åtgärder, använd Entity Framework:

    • Välj TodoItem (TodoApi.Models) i klassen Model.
    • Välj TodoContext (TodoApi.Models) i den datakontextklassen .
    • Välj Lägg till.

    Om scaffolding-åtgärden misslyckas väljer du Lägg till för att prova scaffolding igen.

Den genererade koden:

  • Markerar klassen med attributet [ApiController]. Det här attributet anger att kontrollanten svarar på webb-API-begäranden. Information om specifika beteenden som attributet aktiverar finns i Skapa webb-API:er med ASP.NET Core.
  • Använder DI för att mata in databaskontexten (TodoContext) i kontrollanten. Databaskontexten används i var och en av de CRUD- metoderna i kontrollanten.

ASP.NET Core-mallarna för:

  • Kontrollanter med vyer innehåller [action] i routningsmallen.
  • API-kontrollanter inkluderar inte [action] i routningsmallen.

När [action] token inte finns i routningsmallen inkluderas inte -åtgärden namn (metodnamn) i slutpunkten. Åtgärdens associerade metodnamn används alltså inte i matchande väg.

Uppdatera metoden PostTodoItem create

Uppdatera retursatsen i PostTodoItem för att använda `nameof`-operatorn:

[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);
}

Föregående kod är en HTTP POST metod, vilket anges av attributet [HttpPost]. Metoden hämtar värdet för TodoItem från brödtexten i HTTP-begäran.

För mer information, se Attributdirigering med Http[Verb]-attribut.

Metoden CreatedAtAction:

  • Returnerar en HTTP 201-statuskod om den lyckas. HTTP 201 är standardsvaret för en HTTP POST-metod som skapar en ny resurs på servern.
  • Lägger till en Location-rubrik i svaret. Location-huvudet anger URI- för det nyligen skapade to-do objektet. Mer information finns i 10.2.2 201 Skapad.
  • Refererar till åtgärden GetTodoItem för att skapa Location-huvudets URI. Nyckelordet C# nameof används för att undvika hårdkodning av åtgärdsnamnet i CreatedAtAction-anropet.

Test PostTodoItem

  • Kör appen genom att trycka på Ctrl+F5.

  • I swagger-webbläsarfönstret väljer du POST /api/TodoItemsoch väljer sedan Prova.

  • Uppdatera JSON i inmatningsfönstret Begärandetext. Till exempel

    {
      "name": "walk dog",
      "isComplete": true
    }
    
  • Välj Kör

    Swagger POST

Testa platsrubrikens URI

I föregående POST visar Swagger UI location-header under Svarsrubriker. Till exempel location: https://localhost:7260/api/TodoItems/1. Platsrubriken visar URI:n för den skapade resursen.

Så här testar du platsrubriken:

  • I swagger-webbläsarfönstret väljer du GET /api/TodoItems/{id}och väljer sedan Prova.

  • Ange 1 i inmatningsfältet för id och välj sedan Kör.

    Swagger GET

Granska GET-metoderna

Två GET-slutpunkter implementeras:

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

Föregående avsnitt visade ett exempel på vägen /api/todoitems/{id}.

Följ anvisningarna i POST för att lägga till en annan att-göra-post och testa sedan /api/todoitems vägen med hjälp av Swagger.

Den här appen använder en minnesintern databas. Om appen stoppas och startas returnerar inte den föregående GET-begäran några data. Om ingen data returneras, ska POST data till appen.

Routnings- och URL-sökvägar

Attributet [HttpGet] anger en metod som svarar på en HTTP GET begäran. URL-sökvägen för varje metod konstrueras på följande sätt:

  • Börja med mallsträngen i kontrollantens Route-attribut:

    [Route("api/[controller]")]
    [ApiController]
    public class TodoItemsController : ControllerBase
    
  • Ersätt [controller] med namnet på kontrollanten, som enligt konventionen är kontrollantens klassnamn minus suffixet "Controller". I det här exemplet är kontrollantklassnamnet TodoItemsController, så kontrollantnamnet är "TodoItems". ASP.NET Core routning är inte skiftlägeskänsligt.

  • Om attributet [HttpGet] har en routningsmall (till exempel [HttpGet("products")]) lägger du till den i sökvägen. Det här exemplet använder ingen mall. För mer information, se Attributdirigering med Http[Verb]-attribut.

I följande GetTodoItem-metod är "{id}" en platshållarvariabel för den unika identifieraren för det to-do objektet. När GetTodoItem anropas anges värdet för "{id}" i URL:en till metoden i parametern 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;
}

Returnera värden

Returtypen för metoderna GetTodoItems och GetTodoItem är ActionResult<T> typ. ASP.NET Core serialiserar automatiskt objektet till JSON- och skriver JSON i brödtexten i svarsmeddelandet. Svarskoden för den här returtypen är 200 OK, förutsatt att det inte finns några ohanterade undantag. Ohanterade undantag översätts till 5xx-fel.

ActionResult returtyper kan representera ett brett utbud av HTTP-statuskoder. Till exempel kan GetTodoItem returnera två olika statusvärden:

  • Om inget objekt matchar det begärda ID:t returnerar metoden en 404-statusNotFound felkod.
  • Annars returnerar metoden 200 med en JSON-svarstext. Om du returnerar item resulterar det i ett HTTP 200 svar.

PutTodoItem-metoden

Granska metoden PutTodoItem:

[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 liknar PostTodoItem, förutom att den använder HTTP PUT. Svaret är 204 (inget innehåll). Enligt HTTP-specifikationen kräver en PUT begäran att klienten skickar hela den uppdaterade entiteten, inte bara ändringarna. Om du vill ha stöd för partiella uppdateringar använder du HTTP PATCH-.

Testa metoden PutTodoItem

Det här exemplet använder en minnesintern databas som måste initieras varje gång appen startas. Det måste finnas ett objekt i databasen innan du gör ett PUT-anrop. Anropa GET för att se till att det finns ett objekt i databasen innan du gör ett PUT-anrop.

Använd knappen PUT med swagger-användargränssnittet för att uppdatera TodoItem som har ID = 1 och ange dess namn till "feed fish". Observera att svaret är HTTP 204 No Content.

Metoden DeleteTodoItem

Granska metoden DeleteTodoItem:

[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();
}

Testa metoden DeleteTodoItem

Använd Swagger-användargränssnittet för att ta bort TodoItem som har ID = 1. Observera att svaret är HTTP 204 No Content.

Testa med andra verktyg

Det finns många andra verktyg som kan användas för att testa webb-API:er, till exempel:

Mer information finns i:

Förhindra överpublicering

För närvarande exponerar exempelappen hela TodoItem objektet. Produktionsappar begränsar vanligtvis de data som matas in och returneras med hjälp av en delmängd av modellen. Det finns flera orsaker till detta, och säkerheten är viktig. Delmängden av en modell kallas vanligtvis för ett dataöverföringsobjekt (DTO), indatamodell eller vymodell. DTO- används i den här handledningen.

En DTO kan användas för att:

  • Förhindra överpublicering.
  • Dölj egenskaper som klienter inte ska visa.
  • Utelämna vissa egenskaper för att minska nyttolaststorleken.
  • Platta ut objektdiagram som innehåller kapslade objekt. Utplattade objektdiagram kan vara enklare för klienter.

Om du vill demonstrera DTO-metoden uppdaterar du klassen TodoItem så att den innehåller ett hemligt fält:

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; }
    }
}

Det hemliga fältet måste vara dolt från den här appen, men en administrativ app kan välja att exponera det.

Kontrollera att du kan skicka och hämta det hemliga fältet.

Skapa en DTO-modell:

namespace TodoApi.Models;

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

Uppdatera TodoItemsController för att använda TodoItemDTO:

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
       };
}

Kontrollera att du inte kan publicera eller hämta det hemliga fältet.

Anropa webb-API:et med JavaScript

Se Självstudie: Anropa ett ASP.NET Core-webb-API med JavaScript.

Videoserie för webb-API

Se Video om: Ny serie för nybörjare om web API:er.

Mönster för företagswebbappar

Vägledning om hur du skapar en tillförlitlig, säker, högpresterande, testbar och skalbar ASP.NET Core-app finns i Enterprise-webbappmönster. En komplett exempelwebbapp av produktionskvalitet som implementerar mönstren är tillgänglig.

Lägga till autentiseringsstöd i ett webb-API

ASP.NET Core Identity lägger till inloggningsfunktioner för användargränssnitt (UI) i ASP.NET Core-webbappar. Om du vill skydda webb-API:er och SPA:er använder du något av följande:

Duende Identity Server är ett OpenID Connect- och OAuth 2.0-ramverk för ASP.NET Core. Duende Identity Server aktiverar följande säkerhetsfunktioner:

  • Autentisering som en tjänst (AaaS)
  • Enkel inloggning/av(SSO) över flera programtyper
  • Åtkomstkontroll för API:er
  • Federation Gateway

Viktig

Duende Software kan kräva att du betalar en licensavgift för produktionsanvändning av Duende Identity Server. Mer information finns i Migrera från ASP.NET Core 5.0 till 6.0.

Mer information finns i Duende Identity Server-dokumentationen (Duende Software-webbplatsen).

Publicera till Azure

Information om hur du distribuerar till Azure finns i Snabbstart: Distribuera en ASP.NET webbapp.

Ytterligare resurser

Visa eller ladda ner exempelkod för den här handledningen. Läs så här laddar du ned.

Mer information finns i följande resurser:

I den här självstudien lär du dig grunderna i att skapa ett kontrollantbaserat webb-API som använder en databas. En annan metod för att skapa API:er i ASP.NET Core är att skapa minimala API:er. Hjälp med att välja mellan minimala API:er och kontrollantbaserade API:er finns i översikten över API:er. En självstudiekurs om hur du skapar ett minimalt API finns i Självstudie: Skapa ett minimalt API med ASP.NET Core.

Överblick

I den här handledningen skapas följande API:

API Beskrivning Begäranens innehåll Svarskropp
GET /api/todoitems Hämta alla to-do objekt Ingen Matris med to-do objekt
GET /api/todoitems/{id} Hämta ett objekt efter ID Ingen Att göra-objekt
POST /api/todoitems Lägga till ett nytt objekt Att göra-objekt Att göra-objekt
PUT /api/todoitems/{id} Uppdatera ett befintligt objekt Att göra-objekt Ingen
DELETE /api/todoitems/{id}     Ta bort ett objekt Ingen Ingen

Följande diagram visar appens design.

Klienten representeras av en ruta till vänster. Den skickar en begäran och får ett svar från programmet, en ruta som ritats till höger. I programrutan representerar tre rutor kontrollanten, modellen och dataåtkomstskiktet. Begäran kommer till programmets kontrollant och läs-/skrivåtgärder sker mellan kontrollanten och dataåtkomstlagret. Modellen serialiseras och returneras till klienten i svaret.

Förutsättningar

Skapa ett webbprojekt

  • På menyn Arkiv väljer du Nytt>Projekt.
  • Ange Web-API i sökrutan.
  • Välj mallen ASP.NET Core Web API och välj Nästa.
  • I dialogrutan Konfigurera det nya projektetnamnger du projektet TodoApi och väljer Nästa.
  • I dialogrutan Ytterligare information:
    • Bekräfta att Framework är .NET 8.0 (support på lång sikt).
    • Bekräfta kryssrutan för Använd kontrollanter (avmarkera om du vill använda minimala API:er) är markerad.
    • Bekräfta att kryssrutan för Aktivera OpenAPI-stöd är markerad.
    • Välj Skapa.

Lägga till ett NuGet-paket

Ett NuGet-paket måste läggas till för att stödja databasen som används i den här guiden.

  • På menyn Verktyg väljer du NuGet Package Manager > Manage NuGet Packages for Solution.
  • Välj fliken Bläddra.
  • Ange Microsoft.EntityFrameworkCore.InMemory i sökrutan och välj sedan Microsoft.EntityFrameworkCore.InMemory.
  • Markera kryssrutan Project i panelen till höger och välj sedan Install.

Anteckning

Mer information om hur du lägger till paket i .NET-appar finns i artiklarna under Installera och hantera paketArbetsflöde för paketförbrukning (NuGet-dokumentation). Bekräfta rätt paketversioner på NuGet.org.

Testa projektet

Projektmallen skapar ett WeatherForecast API med stöd för Swagger.

Tryck på Ctrl+F5 för att köra utan felsökningsprogrammet.

Visual Studio visar följande dialogruta när ett projekt ännu inte har konfigurerats för att använda SSL:

Det här projektet är konfigurerat att använda SSL. För att undvika SSL-varningar i webbläsaren kan du välja att lita på det självsignerade certifikat som IIS Express har genererat. Vill du lita på IIS Express SSL-certifikatet?

Välj Ja om du litar på IIS Express SSL-certifikatet.

Följande dialogruta visas:

säkerhetsvarningsdialog

Välj Ja om du samtycker till att lita på utvecklingscertifikatet.

Information om hur du kan lita på webbläsaren Firefox finns i Firefox SEC_ERROR_INADEQUATE_KEY_USAGE certifikatfel.

Visual Studio startar standardwebbläsaren och navigerar till https://localhost:<port>/swagger/index.html, där <port> är ett slumpmässigt valt portnummer som anges när projektet skapas.

Swagger-sida /swagger/index.html visas. Välj GET>Prova>Kör. Sidan visar:

  • Kommandot Curl för att testa WeatherForecast-API:et.
  • URL:en för att testa WeatherForecast-API:et.
  • Svarskoden, brödtexten och rubrikerna.
  • En listruta med medietyper och exempelvärdet och schemat.

Om Swagger-sidan inte visas kan du läsa detta GitHub-ärende.

Swagger används för att generera användbar dokumentation och hjälpsidor för webb-API:er. I den här handledningen används Swagger för att testa appen. Mer information om Swagger finns i ASP.NET Core web API-dokumentation med Swagger/OpenAPI.

Kopiera och klistra in url:en för begäran i webbläsaren: https://localhost:<port>/weatherforecast

JSON som liknar följande exempel returneras:

[
    {
        "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"
    }
]

Lägga till en modellklass

En modell är en uppsättning klasser som representerar de data som appen hanterar. Modellen för den här appen är klassen TodoItem.

  • Högerklicka på projektet i Solution Explorer. Välj Lägg till>ny mapp. Ge mappen namnet Models.
  • Högerklicka på mappen Models och välj Lägg till>klass. Ge klassen namnet TodoItem och välj Lägg till.
  • Ersätt mallkoden med följande:
namespace TodoApi.Models;

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

Egenskapen Id fungerar som den unika nyckeln i en relationsdatabas.

Modellklasser kan placeras var som helst i projektet, men mappen Models används enligt konvention.

Lägga till en databaskontext

Den databaskontexten är huvudklassen som samordnar Entity Framework-funktioner för en datamodell. Den här klassen skapas genom att härledas från klassen Microsoft.EntityFrameworkCore.DbContext.

  • Högerklicka på mappen Models och välj Lägg till>klass. Ge klassen namnet TodoContext och klicka på Lägg till.
  • Ange följande kod:

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

Registrera databaskontexten

I ASP.NET Core måste tjänster som DB-kontexten registreras i beroendeinjektion (DI)-containern. Containern tillhandahåller tjänsten till kontrollanter.

Uppdatera Program.cs med följande markerade kod:

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();

Föregående kod:

  • Lägger till using direktiv.
  • Lägger till databaskontexten i DI-containern.
  • Anger att databaskontexten ska använda en minnesintern databas.

Generera en styrenhet

  • Högerklicka på mappen Controllers.

  • Välj Lägg till>New Scaffolded Item.

  • Välj API-kontrollant med åtgärder, använd Entity Frameworkoch välj sedan Lägg till.

  • I dialogrutan Lägg till API-kontroller med åtgärder, använd Entity Framework:

    • Välj TodoItem (TodoApi.Models) i klassen Model.
    • Välj TodoContext (TodoApi.Models) i den datakontextklassen .
    • Välj Lägg till.

    Om scaffolding-åtgärden misslyckas väljer du Lägg till för att prova scaffolding igen.

Den genererade koden:

  • Markerar klassen med attributet [ApiController]. Det här attributet anger att kontrollanten svarar på webb-API-begäranden. Information om specifika beteenden som attributet aktiverar finns i Skapa webb-API:er med ASP.NET Core.
  • Använder DI för att mata in databaskontexten (TodoContext) i kontrollanten. Databaskontexten används i var och en av de CRUD- metoderna i kontrollanten.

ASP.NET Core-mallarna för:

  • Kontrollanter med vyer innehåller [action] i routningsmallen.
  • API-kontrollanter inkluderar inte [action] i routningsmallen.

När [action] token inte finns i routningsmallen inkluderas inte -åtgärden namn (metodnamn) i slutpunkten. Åtgärdens associerade metodnamn används alltså inte i matchande väg.

Uppdatera metoden PostTodoItem create

Uppdatera retursatsen i PostTodoItem så att den använder nameof operatorn:

[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);
}

Föregående kod är en HTTP POST metod, vilket anges av attributet [HttpPost]. Metoden hämtar värdet för TodoItem från brödtexten i HTTP-begäran.

För mer information, se Attributdirigering med Http[Verb]-attribut.

Metoden CreatedAtAction:

  • Returnerar en HTTP 201-statuskod om den lyckas. HTTP 201 är standardsvaret för en HTTP POST-metod som skapar en ny resurs på servern.
  • Lägger till en Location-rubrik i svaret. Location-huvudet anger URI- för det nyligen skapade to-do objektet. Mer information finns i 10.2.2 201 Skapad.
  • Refererar till åtgärden GetTodoItem för att skapa Location-huvudets URI. Nyckelordet C# nameof används för att undvika hårdkodning av åtgärdsnamnet i CreatedAtAction-anropet.

Test PostTodoItem

  • Kör appen genom att trycka på Ctrl+F5.

  • I swagger-webbläsarfönstret väljer du POST /api/TodoItemsoch väljer sedan Prova.

  • Uppdatera JSON i inmatningsfönstret Begärandetext. Till exempel

    {
      "name": "walk dog",
      "isComplete": true
    }
    
  • Välj Kör

    Swagger POST

Testa platsrubrikens URI

I föregående POST visar Swagger-användargränssnittet platsrubriken under Svarsrubriker. Till exempel location: https://localhost:7260/api/TodoItems/1. Platsrubriken visar URI:n för den skapade resursen.

Så här testar du platsrubriken:

  • I swagger-webbläsarfönstret väljer du GET /api/TodoItems/{id}och väljer sedan Prova.

  • Ange 1 i inmatningsfältet för id och välj sedan Kör.

    Swagger GET

Granska GET-metoderna

Två GET-slutpunkter implementeras:

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

Föregående avsnitt visade ett exempel på vägen /api/todoitems/{id}.

Följ anvisningarna i POST för att lägga till en annan att-göra-post och testa sedan /api/todoitems vägen med hjälp av Swagger.

Den här appen använder en minnesintern databas. Om appen stoppas och startas returnerar inte den föregående GET-begäran några data. Om ingen data returneras, ska POST data till appen.

Routnings- och URL-sökvägar

Attributet [HttpGet] anger en metod som svarar på en HTTP GET begäran. URL-sökvägen för varje metod konstrueras på följande sätt:

  • Börja med mallsträngen i kontrollantens Route-attribut:

    [Route("api/[controller]")]
    [ApiController]
    public class TodoItemsController : ControllerBase
    
  • Ersätt [controller] med namnet på kontrollanten, som enligt konventionen är kontrollantens klassnamn minus suffixet "Controller". I det här exemplet är kontrollantklassnamnet TodoItemsController, så kontrollantnamnet är "TodoItems". ASP.NET Core routning är inte skiftlägeskänsligt.

  • Om attributet [HttpGet] har en routningsmall (till exempel [HttpGet("products")]) lägger du till den i sökvägen. Det här exemplet använder ingen mall. För mer information, se Attributdirigering med Http[Verb]-attribut.

I följande GetTodoItem-metod är "{id}" en platshållarvariabel för den unika identifieraren för det to-do objektet. När GetTodoItem anropas anges värdet för "{id}" i URL:en till metoden i parametern 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;
}

Returnera värden

Returtypen för metoderna GetTodoItems och GetTodoItem är ActionResult<T> typ. ASP.NET Core serialiserar automatiskt objektet till JSON- och skriver JSON i brödtexten i svarsmeddelandet. Svarskoden för den här returtypen är 200 OK, förutsatt att det inte finns några ohanterade undantag. Ohanterade undantag översätts till 5xx-fel.

ActionResult returtyper kan representera ett brett utbud av HTTP-statuskoder. Till exempel kan GetTodoItem returnera två olika statusvärden:

  • Om inget objekt matchar det begärda ID:t returnerar metoden en 404-statusNotFound felkod.
  • Annars returnerar metoden 200 med en JSON-svarstext. Om du returnerar item resulterar det i ett HTTP 200 svar.

PutTodoItem-metoden

Granska metoden PutTodoItem:

[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 liknar PostTodoItem, förutom att den använder HTTP PUT. Svaret är 204 (inget innehåll). Enligt HTTP-specifikationen kräver en PUT begäran att klienten skickar hela den uppdaterade entiteten, inte bara ändringarna. Om du vill ha stöd för partiella uppdateringar använder du HTTP PATCH-.

Testa metoden PutTodoItem

Det här exemplet använder en minnesintern databas som måste initieras varje gång appen startas. Det måste finnas ett objekt i databasen innan du gör ett PUT-anrop. Anropa GET för att se till att det finns ett objekt i databasen innan du gör ett PUT-anrop.

Använd knappen PUT med swagger-användargränssnittet för att uppdatera TodoItem som har ID = 1 och ange dess namn till "feed fish". Observera att svaret är HTTP 204 No Content.

DeleteTodoItem-metoden

Granska metoden DeleteTodoItem:

[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();
}

Testa metoden DeleteTodoItem

Använd Swagger-användargränssnittet för att ta bort TodoItem som har ID = 1. Observera att svaret är HTTP 204 No Content.

Testa med andra verktyg

Det finns många andra verktyg som kan användas för att testa webb-API:er, till exempel:

Mer information finns i:

Förhindra överpublicering

För närvarande exponerar exempelappen hela TodoItem objektet. Produktionsappar begränsar vanligtvis de data som matas in och returneras med hjälp av en delmängd av modellen. Det finns flera orsaker till detta, och säkerheten är viktig. Delmängden av en modell kallas vanligtvis för ett dataöverföringsobjekt (DTO), indatamodell eller vymodell. DTO- används i den här handledningen.

En DTO kan användas för att:

  • Förhindra överpublicering.
  • Dölj egenskaper som klienter inte ska visa.
  • Utelämna vissa egenskaper för att minska nyttolaststorleken.
  • Platta ut objektdiagram som innehåller kapslade objekt. Utplattade objektdiagram kan vara enklare för klienter.

Om du vill demonstrera DTO-metoden uppdaterar du klassen TodoItem så att den innehåller ett hemligt fält:

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; }
    }
}

Det hemliga fältet måste vara dolt från den här appen, men en administrativ app kan välja att exponera det.

Kontrollera att du kan publicera och hämta det hemliga fältet.

Skapa en DTO-modell:

namespace TodoApi.Models;

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

Uppdatera TodoItemsController för att använda TodoItemDTO:

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
       };
}

Kontrollera att du inte kan publicera eller hämta det hemliga fältet.

Anropa webb-API:et med JavaScript

Se Självstudie: Anropa ett ASP.NET Core-webb-API med JavaScript.

Videoserie för webb-API

Se Video om: Ny serie för nybörjare om web API:er.

Mönster för företagswebbappar

Vägledning om hur du skapar en tillförlitlig, säker, högpresterande, testbar och skalbar ASP.NET Core-app finns i Enterprise-webbappmönster. En komplett exempelwebbapp av produktionskvalitet som implementerar mönstren är tillgänglig.

Lägga till autentiseringsstöd i ett webb-API

ASP.NET Core Identity lägger till inloggningsfunktioner för användargränssnitt (UI) i ASP.NET Core-webbappar. Om du vill skydda webb-API:er och SPA:er använder du något av följande:

Duende Identity Server är ett OpenID Connect- och OAuth 2.0-ramverk för ASP.NET Core. Duende Identity Server aktiverar följande säkerhetsfunktioner:

  • Autentisering som en tjänst (AaaS)
  • Enkel inloggning/av(SSO) över flera programtyper
  • Åtkomstkontroll för API:er
  • Federation Gateway

Viktig

Duende Software kan kräva att du betalar en licensavgift för produktionsanvändning av Duende Identity Server. Mer information finns i Migrera från ASP.NET Core 5.0 till 6.0.

Mer information finns i Duende Identity Server-dokumentationen (Duende Software-webbplatsen).

Publicera till Azure

Information om hur du distribuerar till Azure finns i Snabbstart: Distribuera en ASP.NET webbapp.

Ytterligare resurser

Visa eller ladda ner exempelkod för den här handledningen. Se hur du laddar ned.

Mer information finns i följande resurser: