For at integrere EF Core (Entity Framework Core) med GraphQL i en applikation som f.eks. Northwind-databasen, er det nødvendigt at tilføje specifikke Hot Chocolate-pakker, der letter integrationen af EF Core-databasens kontekst med GraphQL-forespørgselsklasser. Dette kræver et par enkle skridt.

Først skal du tilføje den relevante pakke for Hot Chocolate, som giver mulighed for nemt at tilføje EF Core-understøttelse i projektet. Pakken tilføjes ved at reference den relevante Hot Chocolate-integration sammen med en projekt-reference til Northwind-databasen. Vær opmærksom på, at alle Hot Chocolate-pakker skal have den samme version for at sikre kompatibilitet og undgå problemer med afhængigheder. Det er også vigtigt, at stien til projektet ikke indeholder linjeskift, da dette kan føre til fejl under kompilering.

Når pakken er tilføjet, kan du bygge projektet via kommandolinjen eller terminalen ved hjælp af kommandoen dotnet build. Hvis du refererer til et projekt uden for den nuværende løsning, skal du bygge projektet mindst én gang fra kommandolinjen eller terminalen, før Visual Studio 2022 kan kompileres korrekt via Byg-menuen.

Herefter skal du importere det nødvendige namespace i Program.cs, så du kan arbejde med EF Core-modellen for Northwind-databasen. Dette gøres ved at tilføje følgende linje:

csharp
using Packt.Shared; // AddNorthwindContext extension method

Dernæst, efter oprettelsen af builder, skal du registrere Northwind-databasens kontekstklasse i DI-containeren og tilføje GraphQL-server-understøttelsen. Dette gør du med følgende kode:

csharp
builder.Services.AddNorthwindContext();
builder.Services .AddGraphQLServer() .RegisterDbContext() .AddQueryType();

Når dette er gjort, kan du begynde at definere GraphQL-forespørgsler i Query.cs-filen. Her kan du oprette objektgraph-typer og definere forespørgsler som returnerer kategorier, en enkelt kategori, produkter for en kategori og alle produkter i databasen. Et eksempel på en sådan forespørgsel ser således ud:

csharp
public IQueryable<Category> GetCategories(NorthwindContext db) =>
db.Categories.Include(c => c.Products); public Category? GetCategory(NorthwindContext db, int categoryId) { Category? category = db.Categories.Find(categoryId); if (category == null) return null; db.Entry(category).Collection(c => c.Products).Load(); return category; } public IQueryable<Product> GetProducts(NorthwindContext db) => db.Products.Include(p => p.Category);

Med disse forespørgsler er du nu klar til at teste GraphQL-forespørgsler i Northwind-databasen.

For at teste integrationen, kan du starte GraphQL-tjenesteprojektet, som beskrevet, og derefter bruge Banana Cake Pop, et GraphQL-interface, til at sende forespørgsler. Ved at vælge fanen "Schema Definition" kan du se de tilgængelige typer og forespørgsler for Category og Product. For eksempel kan du sende en forespørgsel for at få alle kategorier med følgende kode:

graphql
query AllCategories { categories { categoryId categoryName description } }

Resultatet af denne forespørgsel vil være en liste af kategorier, f.eks. "Beverages" og "Condiments", med deres tilhørende beskrivelse. På samme måde kan du oprette mere komplekse forespørgsler, der specifikt anmoder om information om produkter inden for en given kategori, eller detaljer om hvert produkt, som f.eks. deres pris og antal på lager.

En sådan forespørgsel kunne se sådan ud:

graphql
query Condiments {
category(categoryId: 2) {
categoryId categoryName products
{ productId productName unitPrice } } }

Når du udfører denne forespørgsel, vil du få et resultat med produkterne i "Condiments"-kategorien, som f.eks. "Aniseed Syrup" og "Chef Anton's Cajun Seasoning" sammen med deres priser.

Det er vigtigt at være opmærksom på, at GraphQL giver mulighed for at hente netop de data, man har brug for, hvilket gør det til et kraftfuldt værktøj til datatilgang. Ved at kombinere EF Core med GraphQL opnår man en fleksibel og effektiv måde at forespørge på store datakilder som Northwind.

Det er også væsentligt at forstå, at GraphQL som en forespørgselssprog ikke bare returnerer statiske data, men tillader dynamiske anmodninger baseret på den ønskede struktur. Når du bygger forespørgsler, er det vigtigt at sikre, at du kun anmoder om de nødvendige felter for at optimere ydeevnen og undgå unødvendige belastninger på serveren.

Derudover bør læseren være opmærksom på sikkerhedsaspekterne ved at eksponere data gennem GraphQL. Det er vigtigt at sikre sig, at kun de rette data er tilgængelige for brugeren og at der er passende godkendelse og autorisation på plads, især når det drejer sig om følsomme informationer.

Hvordan implementerer man gRPC i et EF Core-projekt?

At bygge mikroservices med gRPC og EF Core kræver en veldefineret arkitektur, der gør det muligt for systemet at kommunikere effektivt og hurtigt mellem tjenester. Dette kapitel beskriver, hvordan du kan implementere en gRPC-tjeneste i et projekt, der benytter EF Core, og hvordan du kan integrere det i en webapplikation.

I første omgang skal du oprette en gRPC-tjeneste, der arbejder med Northwind-databasen. Dette kræver, at vi refererer til den EF Core-model, der blev oprettet i kapitel 2 om håndtering af relationel data, og derefter definerer en kontrakt for gRPC-tjenesten via en .proto-fil.

Oprettelse af gRPC-service:

  1. Først skal du tilføje en projektreference til Northwind-databasekonteksten i dit gRPC-projekt. Denne reference gør det muligt for din gRPC-tjeneste at tilgå dataene i Northwind-databasen.

  2. Derefter skal du bygge Northwind.Grpc.Service-projektet, og i Protos-mappen tilføje en ny fil ved navn shipper.proto. I denne fil definerer du den service, som gRPC-tjenesten vil tilbyde. Eksemplet herunder viser, hvordan du definerer en Shipper-service, der returnerer en ShipperReply:

    proto
    syntax = "proto3"; option csharp_namespace = "Northwind.Grpc.Service"; package shipper; service Shipper { rpc GetShipper (ShipperRequest) returns (ShipperReply); } message ShipperRequest { int32 shipperId = 1; } message ShipperReply { int32 shipperId = 1; string companyName = 2; string phone = 3; }
  3. Derefter skal du oprette en serviceklasse, ShipperService.cs, der bruger Northwind-databasekonteksten til at hente og returnere data for en given transportør. Bemærk, at vi ikke kan bruge EF Core-entity-klasserne direkte i gRPC, så vi bruger en hjælpefunktion til at mappe fra EF Core-entiteter til de gRPC-genererede klasser.

Implementering af klient:

For at kunne kommunikere med den gRPC-tjeneste, du har oprettet, skal du også oprette en gRPC-klient. I et MVC-projekt kan du gøre dette ved at følge disse trin:

  1. Kopier shipper.proto-filen fra Northwind.Grpc.Service-projektet til dit klientprojekt.

  2. Ændr namespace i shipper.proto-filen, så det passer til den namespace, der bruges i klientprojektet. Dette sikrer, at de automatisk genererede klasser vil blive placeret i den rigtige namespace.

  3. Registrer .proto-filen i klientprojektet, så gRPC-klienten kan bruge den til at sende og modtage beskeder.

  4. I Program.cs i klientprojektet skal du tilføje en linje, der registrerer klienten og konfigurerer forbindelsen til gRPC-tjenesten:

    csharp
    builder.Services.AddGrpcClient("Shipper", options => { options.Address = new Uri("https://localhost:5121"); });
  5. I HomeController.cs kan du nu oprette en instans af ShipperClient og bruge den til at hente en transportør ved at kalde den relevante gRPC-metode:

    csharp
    public async Task Index(string name = "Henrietta", int id = 1)
    { try { HelloReply reply = await greeterClient.SayHelloAsync(new HelloRequest { Name = name }); ViewData["greeting"] = "Greeting from gRPC service: " + reply.Message; ShipperReply shipperReply = await shipperClient.GetShipperAsync(new ShipperRequest { ShipperId = id }); ViewData["shipper"] = $"Shipper from gRPC service: ID: {shipperReply.ShipperId}, Name: {shipperReply.CompanyName}, Phone: {shipperReply.Phone}."; } catch (Exception ex) { _logger.LogWarning($"Northwind.Grpc.Service is not responding."); ViewData["exception"] = ex.Message; } return View(); }

Vigtige overvejelser og yderligere implementering:

Når du bygger en gRPC-tjeneste og -klient som beskrevet, er der flere vigtige faktorer at overveje for at sikre systemets effektivitet og robusthed.

Først og fremmest er det vigtigt at bemærke, at gRPC er ideelt til scenarier, hvor lav latenstid og høj ydeevne er kritiske. I modsætning til REST, der er baseret på HTTP/1.1, bruger gRPC HTTP/2, hvilket muliggør multiplexing af flere forespørgsler over en enkelt forbindelse. Dette kan føre til betydelige ydeevneforbedringer, især i scenarier med høj trafik.

Desuden skal du tage højde for fejlhåndtering og logging. Selvom gRPC er effektivt, kan forbindelser mislykkes, og det er vigtigt at have robust fejlhåndtering på både server- og klientsiden. Dette kan inkludere tidsgrænser for anmodninger, automatiske genforsøg og korrekt logning af fejl, som vist i eksemplet med try-catch-blokken i HomeController.cs.

For klienten er det også vigtigt at huske på, at gRPC ikke automatisk håndterer tilstand eller sessioner. Hvis du har brug for at gemme brugerens tilstand mellem anmodninger, skal du implementere dette selv, f.eks. ved at bruge sessioner eller andre metoder til at opretholde brugerspecifik data.

Ved implementeringen af gRPC i et EF Core-projekt kan AutoMapper være en god hjælp til at kortlægge mellem EF Core-entiteter og de beskeder, som gRPC bruger. Selvom vi her har valgt at implementere kortlægningen manuelt, kan AutoMapper effektivisere denne proces i mere komplekse systemer.

Endelig, når du arbejder med gRPC, er det vigtigt at have en sikker tilgang. Brug af HTTPS, autentifikation og autorisation bør være på plads for at beskytte data og sikre, at kun autoriserede klienter kan tilgå gRPC-tjenesterne.