Del via


Kapittel 5: Opprette og publisere en nett-API i Azure

Etter å ha fastslått at dataene for reparatørenes app skal komme fra eksisterende systemer via en nett-API, samarbeider Maria og Kiana for å finne ut nøyaktig hvilken informasjon som er nødvendig, og i hvilket format. Kiana oppretter deretter et webprogram som viser riktig nett-API og sørger for at den driftes i Azure. Appen kan koble til Azure fra hvor som helst der det er en trådløs tilkobling.

Definere nett-API-operasjoner: Administrasjon av feltbeholdning

Bla gjennom-skjermbildet i delen Administrasjon av feltbeholdning i appen viser en liste over deler for kokere og klimaanleggsystemer (referert til bare som kokerdeler). I skjermbildet Detaljer kan reparatøren vise mer informasjon om en valgt del.

I den eksisterende lagerdatabasen (kalt InventoryDB) lagres informasjon om deler i en enkelt tabell kalt BoilerParts. Kiana bestemmer seg for at nett-API-en skal støtte følgende forespørsler:

  • Hent alle kokerdeler.
  • Få detaljene for en del, gitt del-ID-en.

Definere nett-API-operasjoner: Kunnskapsbase i felten

I det eksisterende systemet inneholder kunnskapsbasedatabasen (kalt KnowledgeDB) tre tabeller som registrerer og administrerer relasjoner blant tips, ingeniører og deler:

  • Tips, som inneholder detaljene for et tips. Hvert tips består av et enkelt linjesammendrag som identifiserer et bestemt problem (emnet), og en mer detaljert forklaring som beskriver hvordan problemet kan løses (brødteksten). Hvert tips refererer også til en del, og ingeniøren som registrerte tipset.
  • BoilerParts, som inneholder en liste over delene tips refererer til. Detaljene for delene lagres i tabellen BoilerParts i InventoryDB-databasen.
  • Ingeniører, som viser reparatørene som har skrevet hvert tips.

Kunnskapsbasedelen av appen inneholder for øyeblikket bare en plassholder for nettleserskjermen. Maria vil implementere følgende funksjonalitet:

  • Teknikeren angir et søkeord på Bla gjennom-skjermen for å finne alle samsvarende tips. Matchen kan være i navnet på delen som tipset refererer til, tekst i emnet eller brødteksten i tipset, eller navnet på en reparatør som er ekspert med et bestemt utstyr.

  • Når alle samsvarende tips er funnet, kan reparatøren velge et tips for å vise detaljene.

  • En reparatør kan også legge til nye tips i kunnskapsbasen, og legge til notater og kommentarer i eksisterende tips.

    Kunnskapsbasen er stor og vokser, og spørring på tvers av flere tabeller og kolonner kan inneholde kompleks logikk som krever betydelig beregningskraft. For å redusere belastningen på nett-API-en bestemmer Kiana seg for å bruke Azure Cognitive Search til å gi søkefunksjonaliteten, som beskrevet tidligere. For å støtte appen avgjør Kiana at følgende operasjoner kreves fra nett-API-en:

  • Finn detaljene for et bestemt kunnskapsbasetips fra Tips-tabellen.

  • Oppdater et eksisterende kunnskapsbasetips i Tips-tabellen.

  • Legg til et nytt kunnskapsbasetips i Tips-tabellen, som også kan innebære å legge til rader i tabellene BoilerParts og Reparatører, hvis den angitte delen eller reparatøren ikke har noen tips registrert mot seg for øyeblikket. Rutinen som faktisk utfører logikken bak det å legge til et nytt tips, implementeres som en logikkapp som kalles fra Power Apps.

Definere nett-API-operasjoner: Planlegging i felten

Planlegging av reparatøravtaler krever ikke bare spørring, tillegging og fjerning av avtaler, men også registrering av informasjon om kunder. Det eksisterende avtalesystemet registrerer disse dataene i tre tabeller i SchedulesDB-databasen:

  • Avtaler, som inneholder detaljene for hver avtale, inkludert dato, klokkeslett, problem, notater og reparatøren som er tilordnet oppgaven.
  • Kunder, som inneholder detaljene for hver kunde, inkludert navn, adresse og kontaktinformasjon.
  • Reparatører, som viser hver reparatør som deltar i avtaler.

Obs!

Databasen inneholder faktisk en fjerde tabell med navnet AppointmentsStatus. Denne tabellen inneholder en liste over gyldige verdier for statusen til en avtale, og er ganske enkelt et oppslag som brukes av andre deler av det eksisterende avtalesystemet.

Kiana avgjør at følgende operasjoner kan være nyttige for feltplanleggingsdelen av appen:

  • Finn alle avtaler for en bestemt reparatør.
  • Finn alle avtaler for gjeldende dag for en bestemt reparatør.
  • Finn den neste planlagte avtalen for en bestemt reparatør.
  • Oppdater detaljene for en avtale, for eksempel legge til notater eller et bilde.
  • Finn detaljer om en kunde.

Bygge nett-API-en: Administrasjon av feltbeholdning

De eksisterende systemene lagrer data ved hjelp av Azure SQL Database. Kiana bestemmer seg for å bygge nett-API-en ved hjelp av Entity Framework Core, fordi denne metoden kan generere mye av koden som spør, setter inn og oppdaterer data automatisk. Nett-API-malen fra Microsoft kan også opprette Swagger-beskrivelsene som beskriver hver operasjon i API-en. Disse beskrivelsene er nyttige for testing av API-operasjoner. Mange verktøy kan bruke denne informasjonen til å integrere API-en med andre tjenester, for eksempel Azure API Management.

Kiana startet med funksjonen for feltbeholdning fordi dette er den mest enkle delen. Feltbeholdningsoperasjonene i nett-API spør én enkelt tabell, BoilerParts, i InventoryDB-databasen. Denne tabellen inneholder kolonnene som vises i bildet nedenfor.

Tabellen BoilerParts viser kolonnene Id, Name, CategoryId, Price, Overview, NumberInStock og ImageURL.

Kiana brukte kode-først-metoden til å bygge nett-API-en og gjorde følgende:

  1. Definerte sin egen C# modell-klasse som gjenspeilet strukturen til BoilerParts-tabellen i InventoryDB-databasen.

  2. Opprettet en kontekst-klasse for enhetsrammeverket som nett-API-en bruker til å koble til databasen, for å kjøre spørringer.

  3. Konfigurerte kontekstklassen til å koble til InventoryDB-databasen i Azure.

  4. Brukte kommandolinjeverktøyene i enhetsrammeverket til å generere en kontroller-klasse for nett-API-en som implementerer HTTP REST-forespørsler for hver av operasjonene som kan utføres mot BoilerParts-tabellen.

  5. Brukte Swagger-API-en til å teste nett-API-en.

Bildet nedenfor viser strukturen på høyt nivå til nett-API-en.

Struktur på høyt nivå i nett-API for beholdning.

Kiana brukte følgende prosedyre til å opprette nett-API.en ved hjelp av .NET 6.0-kommandolinjeverktøyene og Visual Studio Code:

  1. Åpne et terminalvindu i Visual Studio Code.

    Nytt terminalvindu i VS Code.

  2. Kjør følgende kommando for å opprette et nytt nett-API-prosjekt kalt FieldEngineerApi.

    dotnet new webapi -o FieldEngineerApi
    
  3. Åpne mappen FieldEngineerApi.

    Åpne mappen FieldEngineerApi.

  4. Fjern eksempelkontrolleren WeatherForecastController.cs og klassefilen WeatherForecast.cs som ble opprettet av nett-API-malen.

    Slett WeatherForecast-filer.

  5. I Terminal-vinduet legger du til følgende pakker og verktøy i enhetsrammeverket, sammen med støtte for bruk av SQL Server, i prosjektet.

    dotnet add package Microsoft.EntityFrameworkCore.SqlServer
    
    dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
    
    dotnet add package Microsoft.EntityFrameworkCore.Design
    
    dotnet add package Microsoft.AspNetCore.Mvc.NewtonsoftJson
    
    dotnet tool install --global dotnet-ef
    
    dotnet tool install --global dotnet-aspnet-codegenerator
    
  6. I FieldEngineerApi-mappen oppretter du en ny mappe kalt Modeller.

    Opprett Modeller-mappen.

  7. I Modeller-mappen oppretter du en C#-kodefil kalt BoilerPart.cs.

    Opprett BoilerPart-klasse.

  8. I denne filen legger du til følgende egenskaper og felter: Disse egenskapene og feltene gjenspeiler strukturen i BoilerParts-tabellen i InventoryDB-databasen.

    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    
    namespace FieldEngineerApi.Models
    {
    
        public class BoilerPart
        {
            [Key]
            public long Id { get; set; }
    
            public string Name { get; set; }
    
            public string CategoryId { get; set; }
    
            [Column(TypeName = "money")]
            public decimal Price { get; set; }
    
            public string Overview { get; set; }
    
            public int NumberInStock { get; set; }
    
            public string ImageUrl { get; set; }
        }
    }
    
  9. I Modeller-mappen oppretter du en annen C#-kodefil kalt InventoryContext.cs. Legg til følgende kode i denne klassen. Klassen utgjør tilkoblingen mellom kontrolleren (som skal opprettes etterpå) og databasen.

    using Microsoft.EntityFrameworkCore;
    
    namespace FieldEngineerApi.Models
    {
        public class InventoryContext : DbContext
        {
            public InventoryContext(DbContextOptions<InventoryContext> options)
                : base(options)
            {
    
            }
    
            public DbSet\<BoilerPart\> BoilerParts { get; set; }
        }
    }
    
  10. Rediger filen appsettings.Development.json for prosjektet, og legg til en ConnectionStrings-del med følgende InventoryDB-tilkoblingsstreng. Erstatt <server name> med navnet på SQL Database-serveren du opprettet for å være vert for InventoryDB-databasen.

    {
        "ConnectionStrings": {
            "InventoryDB": "Server=tcp*:<server name>*.database.windows.net,1433;Initial Catalog=InventoryDB;Persist Security Info=False;User ID=sqladmin;Password=Pa55w.rd;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
        },
        "Logging": {
            "LogLevel": {
                "Default": "Information",
                "Microsoft": "Warning",
                "Microsoft.Hosting.Lifetime": "Information"
            }
        }
    }
    

    Viktig

    I denne veiledningen inneholder tilkoblingsstrengen bruker-ID-en og passordet for databasen. I et produksjonssystem bør du aldri lagre disse elementene i klartekst i en konfigurasjonsfil.

  11. Rediger Startup.cs, og legg til følgende ved hjelp av direktivene i listen i begynnelsen av filen.

    using FieldEngineerApi.Models;
    using Microsoft.EntityFrameworkCore;
    
  12. I Oppstart-klassen finner du ConfigureServices-metoden. Legg til følgende setning i denne metoden.

    public void ConfigureServices(IServiceCollection services)
    {
    
        services.AddDbContext<InventoryContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("InventoryDB")));
    
        services.AddControllers();
        ...
    }
    
  13. Endre Konfigurer-metoden, og aktiver Swagger-brukergrensesnittet selv om appen kjører i produksjonsmodus, som vist (denne endringen involverer omplassering av de to app.UseSwagger-metodekallene utenfor if-setningen).

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        app.UseSwagger();
        app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "FieldEngineerApi v1"));
    
        ...
    }
    

    Viktig

    Denne endringen gjør at Swagger-endepunktet kan eksponeres for API Management-integrering. Når API Management er konfigurert, må du flytte denne koden tilbake til if-setningen og distribuere nett-API-en på nytt. La aldri Swagger-endepunktet være åpent i et produksjonssystem.

  14. I Terminal-vinduet kjører du følgende kommando for å generere BoilerParts-kontrolleren fra BoilerPart-modellklassen og InventoryContext-kontekstklassen.

    dotnet aspnet-codegenerator controller ^
        -name BoilerPartsController -async -api ^
         -m BoilerPart -dc InventoryContext -outDir Controllers
    

    BoilerParts-kontrolleren må opprettes i Kontrollere-mappen.

    [!NOTE] Linjeavslutningstegnet, ^, gjenkjennes bare av Windows. Hvis du kjører Visual Studio Code på et Linux-system, må du bruke \-tegnet i stedet.

  15. Åpne filen BoilerParts.cs i Kontrollere-mappen, og se gjennom innholdet. BoilerPartsController-klassen viser følgende REST-metoder:

    • GetBoilerParts(), som returnerer en liste over alle BoilerPart-objektene fra databasen.
    • GetBoilerPart(long id), som henter detaljene for den angitte kokerdelen.
    • PutBoilerPart(long id, BoilerPart boilerPart), som oppdaterer en kokerdel i databasen med detaljene i BoilerPart-objektet angitt som en parameter.
    • PostBoilerPart(BoilerPart boilerPart), som oppretter en ny kokerdel.
    • DeleteBoilerPart(long id), som fjerner den angitte kokerdelen fra databasen.

    Obs!

    Teknikerens app krever bare de to Get-metodene, men de andre er nyttige for appen for lagerbeholdning for stasjonær datamaskin (dekkes ikke i denne veiledningen).

  16. Kompiler og byge web-API-en.

    dotnet build
    

Web-API-en skal bygges uten at det rapporteres feil eller advarsler.

Distribusjon av nett-API-en til Azure: Administrasjon av feltbeholdning

Kiana distribuerte og testet web-API-en ved å utføre følgende oppgaver:

  1. Bruk Azure-kontoutvidelsen i Visual Studio Code til å logge på Azure-abonnementet ditt.

  2. Fra Terminal-vinduet i Visual Studio Code oppretter du en ny ressursgruppe kalt for webapi_rg i Azure-abonnementet. I følgende kommando bytter du ut <location> med det nærmeste Azure-området.

    az group create ^
        --name webapi_rg ^
        --location <location>
    
  3. Opprett en Azure App Service-plan for å tilby ressursene for drifting av web-API-en.

    az appservice plan create ^
        --name webapi_plan ^
        --resource-group webapi_rg ^
        --sku F1
    

    Obs!

    F1 er en gratis SKU for App Service-planer. Den gir begrenset gjennomstrømming og kapasitet, og passer bare for utviklingsformål.

  4. Opprett et Azure-webprogram ved hjelp av App Service-planen. Erstatt <webapp name> med et unikt navn for webaprogrammet.

    az webapp create ^
        --name <webapp name> ^
        --resource-group webapi_rg ^
        --plan webapi_plan
    
  5. I Visual Studio Code redigerer du appSettings.json-filen og legger deretter til den samme tilkoblingsstrengen som du skrev tidligere, i appSettings.Development.json-filen. Husk å erstatte <server name> med navnet på SQL Database-serveren du opprettet for å være vert for InventoryDB-databasen.

    {
        "ConnectionStrings": {
            "InventoryDB": "Server=tcp:<server name>.database.windows.net,1433;Initial Catalog=InventoryDB;Persist Security Info=False;User ID=sqladmin;Password=Pa55w.rd;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"**
        },
        "Logging": {
            "LogLevel": {
                "Default\: "Information",
                "Microsoft": "Warning",
                "Microsoft.Hosting.Lifetime": "Information"
            }
        },
        "AllowedHosts": "*"
    }
    
  6. I Terminal-vinduet pakker du nett-API-en klar for distribusjon til Azure.

    dotnet publish -c Release -o ./publish
    

    Denne kommandoen lagrer de pakkede filene i en mappe med navnet Publiser.

  7. I Visual Studio Code høyreklikker du på Publiser-mappen og velger deretter Distribuer til webprogram.

    Distribuer nettprogrammet fra VS Code.

  8. Velg navnet på webprogrammet du opprettet tidligere i trinn 4 (<webapp name>). I følgende eksempel har webprogrammet navnet my-fieldengineer-webapp.

    Velg nettprogrammet.

  9. Ved ledeteksten i Visual Studio Code-dialogen velger du Distribuer for å godta advarselen og distribuere webprogrammet.

    Distribusjonsadvarsel i VS Code.

  10. Kontroller at webprogrammet er distribuert, og gå deretter til nettstedet.

    Dialogboks for å gå til nettstedet i VS Code.

  11. Nettstedet åpnes i et nytt nettleservindu, men det vises en HTTP 404-feil (ikke funnet). Dette skyldes at web-API-operasjonene er tilgjengelige via api-endepunktet i stedet for roten til nettstedet. Endre URL-adressen til https://<webapp name>.azurewebsites.net/api/BoilerParts. Denne URI-en starter GetBoilerParts-metoden i BoilerParts-kontrolleren. Web-API-en skal svare med et JSON-dokument som viser alle standarddelene i InventoryDB-databasen.

    Delelisten som vises i nettleseren.

  12. Endre URL-adressen i nettleseren til https://<webapp name>.azurewebsites.net/swagger. Swagger-API-en skal vises. Dette er et grafisk brukergrensesnitt som gjør det mulig for utviklere å kontrollere og teste hver av operasjonene i et web-API. Det fungerer også som et nyttig dokumentasjonsverktøy.

    Swagger-grensesnittet som viser listen over operasjoner.

  13. Velg GET ved siden av /api/BoilerParts/{id}-endepunktet, og velg deretter Prøv det.

    Skjermbildet "Prøv det" i brukergrensesnittet for Swagger

  14. I id-feltet angir du ID-en for en del og velger deretter Kjør. Denne handlingen kaller GetBoilerPart(long id)-metoden i BoilerParts-kontrolleren. Den returnerer et JSON-dokument med detaljene for delen eller en HTTP 404-feil hvis det ikke finnes noen samsvarende del i databasen.

    Svaret i brukergrensesnittet for Swagger.

  15. Lukk nettleseren, og gå tilbake til Visual Studio Code.

Bygge og distribuere web-API: Kunnskapsbase i felten

Feltkunnskapsbase-operasjonene i nett-API-en virker i tre tabeller i KnowledgeDB-databasen: Tips, BoilerParts og Engineers. Bildet nedenfor viser relasjonene mellom disse tabellene og kolonnene de inneholder.

Relasjoner mellom kunnskapsbasetabeller.

Kiana brukte en lignende metode for Feltkunnskapsbase-databasen som ble brukt i databasen Administrasjon av feltbeholdning, og utførte følgende oppgaver:

  1. Opprett C#-modellklasser som gjenspeiler strukturen i tabellene Tips, BoilerParts og Engineers i KnowledgeDB-databasen. Koden for hver av disse klassene vises i følgende:

    Obs!

    BoilerParts-tabellen i KnowledgeDB-databasen er forskjellig fra BoilerParts-tabellen i InventoryDB-databasen. For å unngå samme navn har modellklassene for tabeller i KnowledgeDB-databasen prefikset KnowledgeBase.

    // KnowledgeBaseTips.cs
    
    using System.ComponentModel.DataAnnotations;
    
    namespace FieldEngineerApi.Models
    {
        public class KnowledgeBaseTip 
        {
            [Key]
            public long Id { get; set; }
    
            public long KnowledgeBaseBoilerPartId { get; set; }
    
            public virtual KnowledgeBaseBoilerPart KnowledgeBaseBoilerPart { get; set; }
    
            public string KnowledgeBaseEngineerId { get; set; }
    
            public virtual KnowledgeBaseEngineer KnowledgeBaseEngineer { get; set; }
    
            public string Subject { get; set; }
    
            public string Body { get; set; }
        }
    }
    

    Obs!

    Id for reparatøren er en streng, ikke et tall. Dette er fordi de eksisterende systemene bruker GUID-er til å identifisere teknikere og andre brukere.

    // KnowledgeBaseBoilerPart.cs
    
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    
    namespace FieldEngineerApi.Models
    {
        public class KnowledgeBaseBoilerPart
        {
            [Key]
            public long Id { get; set; }
    
            public string Name { get; set; }
    
            public string Overview { get; set; }
    
            public virtual ICollection<KnowledgeBaseTip> KnowledgeBaseTips { get; set; }
        }
    }
    
    // KnowledgeBaseEngineer.cs
    
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    
    namespace FieldEngineerApi.Models
    {
        public class KnowledgeBaseEngineer
        {
            [Key]
            public string Id { get; set; }
    
            [Required]
            public string Name { get; set; }
    
            public string ContactNumber { get; set; }
    
            public virtual ICollection<KnowledgeBaseTip> KnowledgeBaseTips { get; set; }
        }
    }
    
  2. Opprett en annen kontekst-klasse for enhetsrammeverket som nett-API-en bruekr til å koble til KnowledgeDB-databasen.

    // KnowledgeBaseContext.cs
    
    using Microsoft.EntityFrameworkCore;
    
    namespace FieldEngineerApi.Models
    {
        public class KnowledgeBaseContext : DbContext
        {
            public KnowledgeBaseContext(DbContextOptions<KnowledgeBaseContext> options)
                : base(options)
            {
    
            }   
    
            public DbSet<KnowledgeBaseBoilerPart> BoilerParts { get; set; }
    
            public DbSet<KnowledgeBaseEngineer> Engineers { get; set; }
    
            public DbSet<KnowledgeBaseTip> Tips { get; set; }
        }
    }
    
  3. Rediger filen appsettings.Development.json for prosjektet, og legg til følgende KnowledgeDB-tilkoblingsstreng i delen ConnectionStrings. Erstatt <server name> med navnet på SQL Database-serveren du opprettet for å være vert for KnowledgeDB-databasen.

    {
        "ConnectionStrings": {
            "InventoryDB": "Server=tcp:...",
            "KnowledgeDB": "Server=tcp:<server name>.database.windows.net,1433;Initial Catalog=KnowledgeDB;Persist Security Info=False;User ID=sqladmin;Password=Pa55w.rd;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
        },
        "Logging": {
            ...
            }
        }
    }
    

    Viktig

    I denne veiledningen inneholder tilkoblingsstrengen bruker-ID-en og passordet for databasen. I et produksjonssystem bør du aldri lagre disse elementene i klartekst i en konfigurasjonsfil.

  4. Rediger Startup.cs-filen, og legg til følgende setninger i ConfigureServices-metoden.

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<InventoryContext>...;
    
        services.AddDbContext<KnowledgeBaseContext>(options =>  
            options.UseSqlServer(Configuration.GetConnectionString("KnowledgeD")));
    
        services.AddControllers().AddNewtonsoftJson(
            options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore**
        );
    
        services.AddControllers();
        ...
    }
    

    Den andre setningen styrer hvordan data serialiseres når de hentes. Noen av modellklassene har referanser til andre modellklasser, som igjen kan referere til flere modellklasser. Noen av disse referansene kan føre til rekursive sløyfer (enhet A refererer til enhet B, som refererer til enhet A, som refererer til enhet B på nytt og så videre). ReferenceLoopHandling-alternativet fører til at serialiseringen ignorerer slike sløyfer i dataene, og returnerer bare en enhet og objektene som den umiddelbart refererer til, men ikke mer.

  5. I Terminal-vinduet kjører du følgende kommando for å generere kontrollere fra modellklassene KnowledgeBaseBoilerTip, KnowledgeBaseBoilerPart og KnowledgeBaseEngineer og kontekstklassen KnowledgeBaseContext.

    dotnet aspnet-codegenerator controller ^
        -name KnowledgeBaseTipController -async -api ^
        -m KnowledgeBaseTip ^
        -dc KnowledgeBaseContext -outDir Controllers
    
    dotnet aspnet-codegenerator controller ^
        -name KnowledgeBaseBoilerPartController -async -api ^
        -m KnowledgeBaseBoilerPart ^
        -dc KnowledgeBaseContext -outDir Controllers
    
    dotnet aspnet-codegenerator controller ^
        -name KnowledgeBaseEngineerController -async -api ^
        -m KnowledgeBaseEngineer ^
        -dc KnowledgeBaseContext -outDir Controllers
    

    Alle de tre kontrollerne må opprettes i Kontrollere-mappen.

  6. Rediger KnowledgeBaseBoilerPartController.cs-filen. Denne filen inneholder koden for KnowledgeBaseBoilerPart-kontrolleren. Den skal følge det samme mønsteret som BoilerPartsController-klassen som ble opprettet tidligere, og vise REST-metoder som gjør det mulig for en klient å liste opp, spørre, sette inn, oppdatere og slette enheter. Legg til følgende GetTipsForPart-metode i kontrolleren.

    [Route("api/[controller]")]
    [ApiController]
    
    public class KnowledgeBaseBoilerPartController : ControllerBase
    {
        private readonly KnowledgeBaseContext _context;
    
        public KnowledgeBaseBoilerPartController(KnowledgeBaseContext context)
        {
            _context = context;
        }
    
        // GET: api/KnowledgeBaseBoilerPart/5/Tips
        [HttpGet("{id}/Tips")]
        public async Task<ActionResult<IEnumerable<KnowledgeBaseTip>>>GetTipsForPart(long id)
        {
            return await _context.Tips.Where(
                t => t.KnowledgeBaseBoilerPartId == id).ToListAsync();
        }
        ...
    }
    

    Denne metoden returnerer alle kunnskapsbasetipsene som refererer til en bestemt del. Den spør Tips-tabellen i databasen via KnowledgeBaseContext-objektet for å finne denne informasjonen.

  7. Rediger KnowledgeBaseEngineerController.cs-filen, og legg til følgende metode i KnowledgeBaseEngineerController-klassen.

    [Route("api/[controller]")]
    [ApiController]
    public class KnowledgeBaseEngineerController : ControllerBase
    {
        private readonly KnowledgeBaseContext _context;
    
        public KnowledgeBaseEngineerController(KnowledgeBaseContext context)
        {
            _context = context;
        }
    
        // GET: api/KnowledgeBaseEngineer/5/Tips
        [HttpGet("{id}/Tips")]
        public async Task\<ActionResult<IEnumerable<KnowledgeBaseTip>>> GetTipsForEngineer(string id)
        {
            return await _context.Tips.Where(t => 
                t.KnowledgeBaseEngineerId == id).ToListAsync();
        }
    
        ...
    }
    

    GetTipsForEngineer-metoden finner alle kunnskapsbasetips som er publisert av den angitte reparatøren.

  8. I Terminal-vinduet kompilerer og bygger du nett-API-en.

    dotnet build
    

    Web-API-en skal bygges uten at det rapporteres feil eller advarsler.

  9. Rediger appSettings.json-filen, og legg til tilkoblingsstrengen for KnowledgeDB-databasen. Denne strengen må være den samme som du tidligere skrev til appSettings.Development.json-filen.

    {
        "ConnectionStrings": {
            "InventoryDB": ...,
            "KnowledgeDB": "Server=tcp:<server name>.database.windows.net,1433;Initial Catalog=KnowledgeDB;Persist Security Info=False;User ID=sqladmin;Password=Pa55w.rd;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
        },
        "Logging": {
            ...
        },
        "AllowedHosts": "*"
    }
    
  10. I Terminal-vinduet pakker du nett-API-en klar for distribusjon til Azure.

    dotnet publish -c Release -o ./publish
    
  11. I Visual Studio Code høyreklikker du på Publiser-mappen og velger deretter Distribuer til webprogram. Distribuer til samme Azure-webprogram som du tidligere har opprettet. Tillat veiviseren å overskrive det eksisterende webprogrammet med den nye koden.

  12. Når distribusjonen er fullført, går du til nettstedet, men endrer URL-adressen i leseren til https://<webapp name>.azurewebsites.net/swagger. Operasjonene for kontrollerne KnowledgeBaseBoilerPart, KnowledgeBaseEngineer og KnowldgeBaseTip skal være oppført, i tillegg til de eksisterende BoilerParts-operasjonene. Kontroller at KnowledgeBaseBoilerPart-operasjoneen inkluderer en GET-operasjon for URI-en /api/KnowledgeBaseBoilerPart/{id}/Tips, og at KnowledgeBaseEngineer-operasjonene inkluderer en GET-operasjon for URI-en /api/KnowledgeBaseEngineer/{id}/Tips.

    Swagger-brukergrensesnitt med nye operasjoner.

Bygge og distribuere web-API: Planlegging i felten

Feltplanleggingsoperasjonene bruker tabellene Appointments, AppointmentStatuses (dette er en enkel oppslagstabell som viser de gyldige avtalestatusverdiene), Customers og Engineers, som vist på følgende bilde. Disse tabellene er lagret i SchedulesDB-databasen.

Relasjoner mellom avtaler og planleggingstabeller.

For å opprette web-API-operasjonene for feltplanleggingsdelen av systemet utførte Kiana følgende oppgaver:

  1. Opprett C#-modellklasser som gjenspeiler strukturen i tabellene AppointmentStatus, Appointments, Customers og Engineers i SchedulesDB-databasen. Følgende kode viser hver av disse klassene.

    Obs!

    Modellklassen for Engineers-tabellen er kalt for ScheduleEngineer for å skille den fra modellen for Engineers-tabellen i InventoryDB-databasen.

    // AppointmentStatus.cs
    
    using Newtonsoft.Json;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    
    namespace FieldEngineerApi.Models
    {
        public class AppointmentStatus {
            [Key]
            public long Id { get; set; }
    
            public string StatusName { get; set; }
            [JsonIgnore]
            public virtual ICollection<Appointment> Appointments { get; set; }
        }
    }
    
    // Appointment.cs
    
    using System;
    using System.ComponentModel.DataAnnotations;
    
    namespace FieldEngineerApi.Models
    {
        public class Appointment
        {
            [Key]
            public long Id { get; set; }
    
            [Required]
            public long CustomerId { get; set; }
    
            public virtual Customer Customer { get; set; }
    
            public string ProblemDetails { get; set; }
    
            [Required]
            public long AppointmentStatusId { get; set; }
    
            public virtual AppointmentStatus AppointmentStatus { get; set; }
    
            public string EngineerId { get; set; }
    
            public virtual ScheduleEngineer Engineer { get ; set; }
    
            [Display(Name = "StartTime")]
            [DataType(DataType.DateTime)]
            [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy H:mm:ss}")]
            public DateTime StartDateTime { get; set; }
    
            public string Notes { get; set; }
    
            public string ImageUrl { get; set; }
        }
    }
    
    // Customer.cs
    
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    
    namespace FieldEngineerApi.Models
    {
        public class Customer
        {
            [Key]
            public long Id { get; set; }
    
            [Required]
            public string Name { get; set; }
    
            public string Address { get; set; }
    
            public string ContactNumber { get; set; }
    
            public virtual ICollection<Appointment> Appointments { get; set; }
        }
    }
    
    // ScheduleEngineer.cs
    using Newtonsoft.Json;
    using System.ComponentModel.DataAnnotations;
    using System.Collections.Generic;
    
    namespace FieldEngineerApi.Models
    {
        public class ScheduleEngineer
        {
            [Key]
            public string Id { get; set; }
    
            [Required]
            public string Name { get; set; }
    
            public string ContactNumber { get; set; }
    
            [JsonIgnore]
            public virtual ICollection<Appointment> Appointments { get; set; }
        }
    }
    
  2. Opprett en kontekst-klasse for enhetsrammeverket som nett-API-en bruker til å koble til SchedulesDB-databasen.

    // ScheduleContext.cs
    
    using System;
    using Microsoft.EntityFrameworkCore;
    
    namespace FieldEngineerApi.Models
    {
        public class ScheduleContext : DbContext
        {
            public ScheduleContext(DbContextOptions<ScheduleContext> options)
                : base(options)
            {
    
            }
    
            public DbSet<Appointment> Appointments { get; set; }
    
            public DbSet<AppointmentStatus> AppointmentStatuses { get; set; }
    
            public DbSet<Customer> Customers { get; set; }
    
            public DbSet<ScheduleEngineer> Engineers { get; set; }
        }
    }
    
  3. Rediger filen appsettings.Development.json for prosjektet, og legg til følgende SchedulesDB-tilkoblingsstreng i delen ConnectionStrings. Erstatt <server name> med navnet på SQL Database-serveren du opprettet for å være vert for KnowledgeDB-databasen.

    {
        "ConnectionStrings": {
            "InventoryDB": "Server=tcp*: ...",
            "KnowledgeDB": "Server=tcp; ... ",
            "SchedulesDB": "Server=tcp:<server name>.database.windows.net,1433;Initial Catalog=SchedulesDB;Persist Security Info=False;User ID=sqladmin;Password=Pa55w.rd;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
        },
        "Logging": {
            ...
            }
        }
    }
    
  4. Rediger Startup.cs-filen, og legg til følgende setning i ConfigureServices-metoden.

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<InventoryContext>...;
    
        services.AddDbContex\<KnowledgeBaseContext>...;
    
        services.AddDbContext<ScheduleContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("SchedulesDB")));
    
        services.AddControllers().AddNewtonsoftJson(...);
    
        ...
    }
    
  5. I Terminal-vinduet kjører du følgende kommando for å generere kontrollere fra modellklassene Appointment, Customer og ScheduleEngineer og kontekstklassen ScheduleContext.

    Obs!

    Ikke opprett en separat kontroller for AppointmentStatus-modellen.

    dotnet aspnet-codegenerator controller ^
        -name AppointmentsController -async -api ^
        -m Appointment ^
        -dc ScheduleContext -outDir Controllers
    
    dotnet aspnet-codegenerator controller ^
        -name CustomerController -async -api ^
        -m Customer ^
        -dc ScheduleContext -outDir Controllers
    
    dotnet aspnet-codegenerator controller ^
        -name ScheduleEngineerController -async -api ^
        -m ScheduleEngineer ^
        -dc ScheduleContext -outDir Controllers
    
  6. Rediger AppointmentsController.cs-filen. I AppointmentsController-klassen finner du GetAppointments-metoden. Endre return-setningen, som vist. Denne endringen sikrer at informasjonen om Customer, Engineer og AppointmentStatus hentes som en del av GET-operasjonen. Disse feltene refererer til andre enheter som ellers ville vært null, på grunn av den trege innlastingsmekanismen i enhetsrammeverket.

    public class AppointmentsController : ControllerBase
    {
        private readonly ScheduleContext _context;
    
        public AppointmentsController(ScheduleContext context)
        {
            _context = context;
        }
    
        // GET: api/Appointments
    
        [HttpGet]
        public async Task<ActionResult<IEnumerable<Appointment>>> GetAppointments()
        {
            return await _context.Appointments
                .Include(c => c.Customer)
                .Include(e => e.Engineer)
                .Include(s => s.AppointmentStatus)
                .ToListAsync();
        }
    
        ...
    }
    
  7. Endre GetAppointment(long id)-metoden i den samme filen, som vist.

    // GET: api/Appointments/5
    [HttpGet("{id}")]
    public async Task<ActionResult<Appointment>> GetAppointment(long id)
    {
        var appointment = _context.Appointments
            .Where(a => a.Id == id)
            .Include(c => c.Customer)
            .Include(e => e.Engineer)
            .Include(s => s.AppointmentStatus);
    
        var appData = await appointment.FirstOrDefaultAsync();
        if (appData == null)
        {
            return NotFound();
        }
    
        return appData;
    }
    

    Denne versjonen av metoden fyller ut feltene Customer, Engineer og AppointmentStatus i en avtale når den hentes (treg innlasting ville ellers gjort at disse feltene var tomme).

  8. Finn PutAppointment-metoden, og erstatt den med følgende kode. Denne versjonen av PutAppointment-metoden bruker feltene i en avtale som en bruker kan endre i appen i stedet for et komplett Appointment-objekt.

    [HttpPut("{id}")]
    public async Task<IActionResult> PutAppointment(long id,
        string problemDetails, string statusName,
        string notes, string imageUrl)
    {
    
        var statusId = _context.AppointmentStatuses.First(s => 
            s.StatusName == statusName).Id;
    
        var appointment = _context.Appointments.First(e => 
            e.Id == id);
    
        if (appointment == null)
        {
            return BadRequest();
        }
    
        appointment.ProblemDetails = problemDetails;
        appointment.AppointmentStatusId = statusId;
        appointment.Notes = notes;
        appointment.ImageUrl = imageUrl;
        _context.Entry(appointment).State = EntityState.Modified;
    
        try
        {
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException)
        {
            if (!AppointmentExists(id))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
    
        return NoContent();
    }
    

    Obs!

    Som en generell regel bør PUT-operasjoner bare endre data som en bruker skal få tillatelse til å oppdatere, ikke nødvendigvis hvert felt i en enhet.

  9. Åpne ScheduleEngineerController.cs-filen, og legg til følgende GetScheduleEngineerAppointments-metode i ScheduleEngineerController-klassen.

    [Route("api/[controller]")]
    [ApiController]
    public class ScheduleEngineerController : ControllerBase
    {
        private readonly ScheduleContext _context;
    
        public ScheduleEngineerController(ScheduleContext context)
        {
            _context = context;
        }
    
        // GET: api/ScheduleEngineer/5/Appointments
        [HttpGet("{id}/Appointments")]
    
        public async Task<ActionResult<IEnumerable<Appointment>>> GetScheduleEngineerAppointments(string id)
        {
            return await _context.Appointments
                .Where(a => a.EngineerId == id)
                .OrderByDescending(a => a.StartDateTime)
                .Include(c => c.Customer)
                .Include(e => e.Engineer)
                .Include(s => s.AppointmentStatus)
                .ToListAsync();
        }
    
        ...
    }
    
    These methods retrieve the appointments for the specified technician.
    
    
  10. Edit the CustomerController.cs file and add the GetAppointments and GetNotes methods, as shown, to the CustomerController class.

    [Route("api/[controller]")]
    [ApiController]
    public class CustomerController : ControllerBase
    {
        private readonly ScheduleContext _context;
    
        public CustomerController(ScheduleContext context)
        {
            _context = context;
        }
    
        //GET: api/Customers/5/Appointments
        [HttpGet("{id}/Appointments")]
        public async Task<ActionResult<IEnumerable<Appointment>>> GetAppointments(long id)
        {
            return await _context.Appointments
                .Where(a => a.CustomerId == id)
                .OrderByDescending(a => a.StartDateTime)
                .ToListAsync();
        }
    
        //GET: api/Customers/5/Notes
        [HttpGet("{id}/Notes")]
        public async Task<ActionResult<IEnumerable<object>>> GetNotes(long id)
        {
            return await _context.Appointments
                .Where(a => a.CustomerId == id)
                .OrderByDescending(a => a.StartDateTime)
                .Select(a => 
                    new {a.StartDateTime, a.ProblemDetails, a.Notes})
                .ToListAsync();
        }
    
        ...
    }
    

    GetAppointments-metoden finner alle avtaler for den angitte kunden. GetNotes-metoden henter alle notatene som reparatøren gjorde ved tidligere besøk til kunden.

  11. Rediger appSettings.json-filen, og legg til tilkoblingsstrengen for KnowledgeDB-databasen. Denne strengen må være den samme som du tidligere skrev til appSettings.Development.json-filen.

    {
        "ConnectionStrings": {
            "InventoryDB": ...,
            "KnowledgeDB": ...,
            "SchedulesDB": "Server=tcp:<server name>.database.windows.net,1433;Initial Catalog=SchedulesDB;Persist Security Info=False;User ID=sqladmin;Password=Pa55w.rd;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
        },
        "Logging": {
            ...
        },
        "AllowedHosts": "*"
    }
    
  12. I Terminal-vinduet kompilerer og bygger du nett-API-en.

    dotnet build
    

    Web-API-en skal bygges uten at det rapporteres feil eller advarsler.

  13. I Terminal-vinduet pakker du nett-API-en klar for distribusjon til Azure.

    dotnet publish -c Release -o ./publish
    
  14. I Visual Studio Code høyreklikker du på Publiser-mappen og velger deretter Distribuer til webprogram. Distribuer til samme Azure-webprogram som du tidligere har opprettet. Tillat veiviseren å overskrive det eksisterende webprogrammet med den nye koden.

  15. Når distribusjonen er fullført, går du til nettstedet, men endrer URL-adressen i leseren til https://<webapp name>.azurewebsites.net/swagger. Kontroller at operasjonene for kontrollerne Appointments, Customer og ScheduleEngineer nå er tilgjengelige.

Web-API-en er nå klar til å innlemmes i appen.