Ćwiczenie — dodanie EF Core do minimalnego API

Ukończone

Jesteś deweloperem w firmie, a Ty i Twoja firma słyszeli o nowym minimalnym interfejsie API. Twój menedżer poprosił Cię o utworzenie projektu, aby móc omówić, czy używać go w następnym projekcie.

Notatka

W tym module używany jest interfejs wiersza polecenia platformy .NET (interfejs wiersza polecenia) i program Visual Studio Code na potrzeby programowania lokalnego. Po ukończeniu tego modułu można zastosować koncepcje przy użyciu programu Visual Studio (Windows), programu Visual Studio dla komputerów Mac (macOS) lub dalszego programowania przy użyciu programu Visual Studio Code (Windows, Linux, & macOS).

W tym module jest używany zestaw .NET 8.0 SDK. Upewnij się, że masz zainstalowany program .NET 8.0, uruchamiając następujące polecenie w preferowanym terminalu poleceń:

dotnet --list-sdks

Zostanie wyświetlone dane wyjściowe podobne do następującego przykładu:

6.0.317 [C:\Program Files\dotnet\sdk]
7.0.401 [C:\Program Files\dotnet\sdk]
8.0.100 [C:\Program Files\dotnet\sdk]

Upewnij się, że na liście znajduje się wersja rozpoczynająca się od 8. Jeśli żadna z nich nie znajduje się na liście lub nie zostanie znalezione polecenie, zainstaluj najnowszy zestaw SDK .NET 8.0.

Konfigurowanie projektu

Najpierw należy utworzyć projekt. Zainstalowano platformę .NET 6 i wszystko jest gotowe do użycia. W tym module dodasz trwałość danych do interfejsu API zarządzania pizzą.

  1. W terminalu utwórz internetowy interfejs API, uruchamiając dotnet new:

    dotnet new web -o PizzaStore -f net8.0
    

    Powinien zostać wyświetlony katalog PizzaStore.

  2. Przejdź do katalogu PizzaStore , wprowadzając następujące polecenie:

    cd PizzaStore
    
  3. Zainstaluj pakiet Swashbuckle:

    dotnet add package Swashbuckle.AspNetCore --version 6.5.0
    
  4. Otwórz projekt w programie Visual Studio Code.

  5. Za pomocą programu Visual Studio Code utwórz plik Pizza.cs w katalogu głównym projektu i nadaj mu następującą zawartość:

    namespace PizzaStore.Models 
    {
        public class Pizza
        {
              public int Id { get; set; }
              public string? Name { get; set; }
              public string? Description { get; set; }
        }
    }
    

    Poprzednia klasa Pizza jest prostym obiektem reprezentującym pizzę. Ten kod jest modelem danych. Później użyjesz programu Entity Framework (EF) Core, aby zamapować ten model danych na tabelę bazy danych.

  6. Otwórz Program.cs i dodaj wyróżniony kod:

    using Microsoft.OpenApi.Models;
    
    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen(c =>
    {
         c.SwaggerDoc("v1", new OpenApiInfo {
             Title = "PizzaStore API",
             Description = "Making the Pizzas you love",
             Version = "v1" });
    });
    
    var app = builder.Build();
    if (app.Environment.IsDevelopment())
    {
       app.UseSwagger();
       app.UseSwaggerUI(c =>
       {
          c.SwaggerEndpoint("/swagger/v1/swagger.json", "PizzaStore API V1");
       });
    }
    
    app.MapGet("/", () => "Hello World!");
    
    app.Run();
    

    Może pojawić się monit z programu Visual Studio Code o dodanie zasobów w celu debugowania projektu. Wybierz Yes w oknie dialogowym.

Dodawanie programu EF Core do projektu

Aby przechowywać elementy na liście to-do, zainstaluj pakiet EntityFrameworkCore.InMemory.

  1. Naciśnij Ctrl+, aby otworzyć terminal w programie Visual Studio Code. W nowym terminalu wprowadź następujący kod, aby dodać pakiet EF Core InMemory:

    dotnet add package Microsoft.EntityFrameworkCore.InMemory --version 8.0
    
  2. Dodaj using Microsoft.EntityFrameworkCore; do góry plików Program.cs i Pizza.cs .

    Teraz, gdy program EF Core został dodany do projektu, możesz połączyć kod z danymi, które chcesz zapisać i wykonać względem niego zapytanie. W tym kroku utworzysz klasę PizzaDb. Klasa PizzaDb wykona następujące zadania:

    • Uwidaczniaj właściwość Pizzas z listy Pizza w bazie danych.
    • Użyj UseInMemoryDatabase, aby podłączyć pamięciową bazę danych. Dane są przechowywane w tym miejscu, o ile aplikacja jest uruchomiona.
  3. Aby skonfigurować bazę danych w pamięci, dodaj następujący kod do dołu pliku Pizza.cs (powyżej końcowego }). W przestrzeni nazw PizzaStore.Models będą dostępne dwie definicje klas.

    class PizzaDb : DbContext
    {
        public PizzaDb(DbContextOptions options) : base(options) { }
        public DbSet<Pizza> Pizzas { get; set; } = null!;
    }
    

    DbContext reprezentuje połączenie lub sesję używaną do wykonywania zapytań i zapisywania wystąpień jednostek w bazie danych.

  4. Dodaj using PizzaStore.Models; do góry pliku Program.cs .

  5. W Program.cs przed wywołaniem metody AddSwaggerGendodaj następujący kod:

    builder.Services.AddDbContext<PizzaDb>(options => options.UseInMemoryDatabase("items"));
    

Zwracanie listy elementów

  • Aby odczytać elementy z listy pizzy, dodaj następujący kod przed wywołaniem app.Run();, aby dodać trasę "/pizzas":

    app.MapGet("/pizzas", async (PizzaDb db) => await db.Pizzas.ToListAsync());
    

Uruchamianie aplikacji

  1. Upewnij się, że wszystkie zmiany zostały zapisane. Uruchom aplikację, wywołując dotnet run w terminalu. Ta akcja spowoduje skompilowanie aplikacji i hostowanie jej na porcie z zakresu od 5000 do 5300. Protokół HTTPS będzie miał wybrany port w zakresie 7000–7300.

    Notatka

    Jeśli chcesz zastąpić zachowanie wyboru losowego portu, możesz ustawić porty do użycia w launchSettings.json.

    dotnet run
    

    Oto jak mogą wyglądać dane wyjściowe w terminalu:

    Building...
     info: Microsoft.Hosting.Lifetime[14]
           Now listening on: https://localhost:7200
     info: Microsoft.Hosting.Lifetime[14]
           Now listening on: http://localhost:5100
     info: Microsoft.Hosting.Lifetime[0]
           Application started. Press Ctrl+C to shut down.
     info: Microsoft.Hosting.Lifetime[0]
           Hosting environment: Development
     info: Microsoft.Hosting.Lifetime[0]
           Content root path: /<path>/PizzaStore
    
  2. W przeglądarce przejdź do https://localhost:{PORT}/swagger. Wybierz przycisk GET /pizzas, a następnie Wypróbuj i wykonaj . Zobaczysz, że lista jest pusta w obszarze Response body.

  3. W terminalu naciśnij Ctrl+C , aby zatrzymać uruchamianie programu.

Tworzenie nowych elementów

Dodajmy POST nowych elementów do listy pizz. W Program.csdodaj następujący kod pod app.MapGet, który utworzyłeś wcześniej.

app.MapPost("/pizza", async (PizzaDb db, Pizza pizza) =>
{
    await db.Pizzas.AddAsync(pizza);
    await db.SaveChangesAsync();
    return Results.Created($"/pizza/{pizza.Id}", pizza);
});

Testowanie interfejsu API

Upewnij się, że wszystkie zmiany zostały zapisane i ponownie uruchom aplikację. Wróć do interfejsu Swagger UI, a teraz powinieneś zobaczyć POST/pizza. Aby dodać nowe elementy do listy pizzy:

  1. Wybierz POST /pizza.

  2. Wybierz pozycję Wypróbuj.

  3. Zastąp treść żądania następującym kodem JSON:

    {
        "name": "Pepperoni",
        "description": "A classic pepperoni pizza"
    }
    
  4. Wybierz pozycję Wykonaj.

Aby przeczytać elementy z listy:

  1. Wybierz GET /pizzas.

  2. Wybierz pozycję Wypróbuj.

  3. Wybierz pozycję Wykonaj.

    Response body będzie zawierać właśnie dodane elementy.

    [
      {
        "id": 1,
        "name": "Pepperoni",
        "description": "A classic pepperoni pizza"
      }
    ]
    
  4. Naciśnij Ctrl+C w terminalu, aby zatrzymać uruchamianie aplikacji. W pozostałej części tego ćwiczenia zatrzymaj i uruchom ponownie aplikację zgodnie z potrzebami, aby przetestować zmiany. Pamiętaj, aby zapisać wszystkie zmiany, zanim przejdziesz do dotnet run!

Pobierz pojedynczy element

Aby uzyskać element według id, dodaj kod do utworzonej wcześniej trasy app.MapPost.

app.MapGet("/pizza/{id}", async (PizzaDb db, int id) => await db.Pizzas.FindAsync(id));

Testowanie pobierania danych według identyfikatora

Aby przetestować tę operację, możesz przejść do https://localhost:{PORT}/pizza/1 lub użyć interfejsu Swagger. Ponieważ używasz bazy danych w pamięci, wcześniej utworzona pizza nie będzie wyświetlana, jeśli aplikacja została ponownie uruchomiona. Dlatego należy użyć operacji POST, aby dodać ją ponownie.

Aktualizowanie elementu

Aby zaktualizować istniejący element, dodaj kod w ramach utworzonej trasy GET /pizza/{id}:

app.MapPut("/pizza/{id}", async (PizzaDb db, Pizza updatepizza, int id) =>
{
      var pizza = await db.Pizzas.FindAsync(id);
      if (pizza is null) return Results.NotFound();
      pizza.Name = updatepizza.Name;
      pizza.Description = updatepizza.Description;
      await db.SaveChangesAsync();
      return Results.NoContent();
});

Test PUT

  1. Wybierz PUT /pizza/{id} w interfejsie Swagger.

  2. Wybierz pozycję Wypróbuj.

  3. W polu tekstowym id wprowadź 1.

  4. Na koniec zaktualizuj Request body. Wklej następujący kod JSON i zmień name na Pineapple.

    {
       "id": 1,
       "name": "Pineapple"
    }
    
  5. Wybierz pozycję Wykonaj.

Aby przetestować kod, przewiń z powrotem do GET /pizza/{id}. Pizza ma teraz nazwę Pineapple.

Usuwanie elementu

Aby usunąć istniejący element, dodaj kod w obszarze PUT /pizza/{id}, który został utworzony wcześniej:

app.MapDelete("/pizza/{id}", async (PizzaDb db, int id) =>
{
   var pizza = await db.Pizzas.FindAsync(id);
   if (pizza is null)
   {
      return Results.NotFound();
   }
   db.Pizzas.Remove(pizza);
   await db.SaveChangesAsync();
   return Results.Ok();
});

Testowanie usuwania

Teraz spróbuj usunąć element przy użyciu interfejsu Swagger.

W tej jednostce dodałeś bibliotekę EF Core do istniejącej minimalistycznej aplikacji API i użyłeś bazy danych w pamięci do przechowywania danych. Następnie dowiesz się, jak używać rzeczywistej bazy danych do przechowywania danych, tak aby utrzymywała się między zamykaniem aplikacji.