Deli putem


5. poglavlje: Kreiranje i objavljivanje Web API-ja u usluzi Azure

Utvrdivši da podaci za aplikaciju tehničara treba da se nabavljaju iz postojećih sistema putem Web API-ja, Slavna i Kata zajedno rade kako bi utvrdile koje su tačno informacije potrebne i u kom formatu. Kata će zatim kreirati veb-aplikaciju koja izlaže odgovarajući Web API i organizovati njeno hostovanje u usluzi Azure. Aplikacija može da se poveže sa uslugom Azure sa bilo kog mesta gde postoji bežična veza.

Definisanje Web API operacija: Upravljanje zalihama na terenu

Ekran Pregledaj u odeljku za upravljanje inventarom na terenu u aplikaciji prikazuje listu delova za kotlove i klimatizacijske sisteme (koji se nazivaju jednostavno delovima kotla). Ekran Detalji omogućava tehničaru da vidi više informacija o izabranom delu.

U postojećoj bazi podataka inventara (pod nazivom InventoriDB), informacije o delovima se održavaju u jednoj tabeli pod nazivom BoilerParts. Kata je utvrdila da Web API treba da podržava sledeće zahteve:

  • Preuzmite sve delove kotla.
  • Saznajte detalje o delu, s obzirom na ID dela.

Definisanje Web API operacija: Baza podataka na terenu

U postojećem sistemu, baza podataka znanja (pod nazivom KnovnovDB) sadrži tri tabele koje beleže i upravljaju odnosima između saveta, inženjera i delova:

  • Saveti, koji sadrži detalje saveta. Svaki savet sadrži sažetak jedne linije koji identifikuje određeni problem ( predmet) i detaljnije objašnjenje koje opisuje kako rešiti problem ( telo). Svaki savet takođe upućuje na deo i inženjera koji je zapisao savet.
  • BoilerParts, koji sadrži listu delova na koje upućuju saveti. Detalji o samim delovima se čuvaju u tabeli BoilerParts u bazi podataka InventoryDB .
  • Inženjeri, koji navodi tehničare koji su autori svakog saveta.

Deo baze znanja u aplikaciji trenutno sadrži samo ekran pretraživača . Slavna želi da primeni sledeću funkcionalnost:

  • Tehničar određuje termin za pretragu na ekranu Pregledaj da pronađe sve odgovarajuće savete. Podudaranje može biti u nazivu dela na koji se savet odnosi, tekstu u temi ili telu saveta ili imenu tehničara koji je stručnjak za određeni komad opreme.

  • Kada se pronađu svi odgovarajući saveti, tehničar može odabrati savet da bi video njegove detalje.

  • Tehničar takođe može dodati nove savete u bazu znanja, kao i da doda napomene i komentare u postojeće savete.

    Baza znanja je velika i raste, a upiti u više tabela i kolona mogu da uključuju složenu logiku koja zahteva značajnu računsku snagu. Da bi smanjila opterećenje Web API-ja, Kata odlučuje da koristi Azure kognitivnu pretragu za pružanje funkcionalnosti pretrage, kao što je ranije opisano. Da bi podržala aplikaciju, Kata odlučuje da su od Web API-ja potrebne sledeće radnje:

  • Pronađite detalje određenog saveta baze znanja iz tabele Saveti .

  • Ažurirajte postojeći savet baze znanja u tabeli Saveti .

  • Dodajte novi savet baze znanja u tabelu Saveti , što takođe može uključivati dodavanje redova u tabele BoilerParts i Engineers ako navedeni deo ili inženjer trenutno nema saveta zabeleženih protiv njih. Rutina koja zaista izvodi logiku koja stoji iza dodavanja novog saveta biće primenjena kao logička aplikacija koja se poziva iz usluge Power Apps.

Definisanje Web API operacija: Zakazivanje na terenu

Planiranje zakazane obaveze za tehničara zahteva ne samo postavljanje upita, dodavanje i uklanjanje zakazanih obaveza, već i beleženje informacija o klijentima. Postojeći sistem imenovanja beleži ove podatke u tri tabele u bazi podataka SchedulesDB :

  • Imenovanja, koja sadrži detalje svakog sastanka, uključujući datum, vreme, problem, beleške i tehničara dodeljenog zadatku.
  • Kupci, koji sadrži detalje svakog kupca, uključujući njihovo ime, adresu i kontakt podatke.
  • Inženjeri, koji navodi svakog tehničara koji prisustvuje sastancima.

Belešku

Baza podataka zapravo sadrži četvrtu tabelu pod nazivom AppointmentsStatus. Ova tabela sadrži listu važećih vrednosti za status zakazane obaveze i to je prosto pronalaženje koje koriste drugi delovi postojećeg sistema zakazanih obaveza.

Kata odlučuje da bi sledeće aktivnosti bile korisne za deo aplikacije za planiranje polja:

  • Pronađite sve zakazane obaveze za navedenog tehničara.
  • Pronađite sve zakazane obaveze za tekući dan za navedenog tehničara.
  • Pronađite sledeću zakazanu obavezu za određenog tehničara.
  • Ažurirajte detalje zakazane obaveze, kao što je dodavanje beleški ili fotografije.
  • Pronađite detalje o klijentu.

Gradnja Web API-ja: Upravljanje zalihama na terenu

Postojeći sistemi skladište podatke pomoću Azure SQL baze podataka. Kata se odlučuje na izgradnju Web API-ja koristeći Osnovni radni okvir za entitete, jer ovaj pristup može generisati mnogo koda koji automatski postavlja upite, ubacuje i ažurira podatke. Web API predložak koji obezbeđuje Microsoft takođe može da kreira Swagger opise koji opisuju svaku operaciju u API-ju. Ovi opisi su korisni za testiranje API operacija. Mnogi alati mogu da koriste ove informacije za integraciju API-ja sa drugim uslugama, kao što je upravljanje Azure API-jem.

Kata je započela sa funkcionalnošću inventara na terenu, jer to je najjednostavniji deo. Operacije inventara polja u Veb API-ju upita jednu tabelu, BoilerParts, u bazi podataka InventoriDB . Ova tabela sadrži kolone prikazane na sledećoj slici.

Tabela BoilerParts koja prikazuje kolone ID, Naziv, ID kategorije, Cena, Pregled, Broj na zalihama i ImageURL.

Kiana je "kod-prvi" pristup izgradnji Veb API-ja i uradio sledeće:

  1. Definisali su sopstvenu klasu C # model koja je odražavala strukturu tabele BoilerParts u bazi podataka InventoryDB .

  2. Kreirana je klasa konteksta Entiti Framevork koju Veb API koristi za povezivanje sa bazom podataka, za obavljanje upita.

  3. Konfigurisana je kontekstna klasa za povezivanje sa bazom podataka InventoryDB u Azuri.

  4. Korišćeni su alati komandne linije Entiti Framevork za generisanje klase kontrolera Veb API-ja koja implementira HTTP REST zahteve za svaku od operacija koje se mogu izvesti u tabeli BoilerParts .

  5. Koristila je Swagger API za testiranje Web API-ja.

Sledeća slika prikazuje strukturu Web API-ja na visokom nivou.

Struktura na visokom nivou Web API-ja za zalihe.

Kata je koristila sledeću proceduru za kreiranje Web API-ja pomoću .NET 6.0 alata za komandnu liniju i Visual Studio Code:

  1. Otvorite prozor terminala u usluzi Visual Studio Code.

    Novi prozor terminala u usluzi VS Code.

  2. Pokrenite sledeću komandu da biste kreirali novi Veb API projekat pod nazivom FieldEngineerApi.

    dotnet new webapi -o FieldEngineerApi
    
  3. Otvorite fasciklu FieldEngineerApi .

    Otvorite fasciklu FieldEngineerApi.

  4. Uklonite example WeatherForecastController.cs kontroler i WeatherForecast.cs datoteku klase koja je kreirana od strane Web API šablona.

    Izbrišite WeatherForecast datoteke.

  5. U prozoru Terminala , dodajte sledeće Entiti Framevork pakete i alate, zajedno sa podrškom za korišćenje SKL Server-a, u projekat.

    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. U folderu FieldEngineerApi kreirajte novu fasciklu pod nazivom Modeli.

    Kreiranje fascikle Models.

  7. U folderu Models , kreirajte C# kodnu datoteku pod nazivom BoilerPart.cs.

    Kreiranje klase BoilerPart.

  8. U ovu datoteku dodajte sledeća svojstva i polja. Ove osobine i polja odražavaju strukturu tabele BoilerParts u bazi podataka InventoryDB .

    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. U folderu Models , kreirajte drugu C# kodnu datoteku pod nazivom InventoryContext.cs. Dodajte sledeći kôd u ovu klasu. Klasa obezbeđuje vezu između kontrolera (koji će se sledeći kreirati) i baze podataka.

    using Microsoft.EntityFrameworkCore;
    
    namespace FieldEngineerApi.Models
    {
        public class InventoryContext : DbContext
        {
            public InventoryContext(DbContextOptions<InventoryContext> options)
                : base(options)
            {
    
            }
    
            public DbSet\<BoilerPart\> BoilerParts { get; set; }
        }
    }
    
  10. Izmenite appsettings. Development.json datoteku za projekat i dodajte odeljak ConnectionStrings sa sledećim nizom veze InventoryDB . Zamenite <ime> servera sa imenom SKL baze podataka servera koji ste kreirali da biste držali bazu podataka InventoriDB .

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

    Važno

    Samo za potrebe ovog vodiča, niska veze sadrži ID korisnika i lozinku za bazu podataka. U proizvodnom sistemu ove stavke nikada ne smete čuvati u čistom tekstu u datoteci za konfiguraciju.

  11. Uredite Startup.cs fajl i dodajte sledeće direktive korišćenja na listu na početku fajla.

    using FieldEngineerApi.Models;
    using Microsoft.EntityFrameworkCore;
    
  12. U klasi Startup pronađite metodu ConfigureServices . Dodajte sledeću naredbu u ovaj metod.

    public void ConfigureServices(IServiceCollection services)
    {
    
        services.AddDbContext<InventoryContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("InventoryDB")));
    
        services.AddControllers();
        ...
    }
    
  13. Izmenite metod Configure i omogućite Svagger UI čak i kada aplikacija radi u proizvodnom režimu, kao što je prikazano (ova promena uključuje premeštanje dve aplikacije. UseSvagger metod poziva izvan if izraza ).

    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"));
    
        ...
    }
    

    Važno

    Ova promena omogućava da Swagger krajnja tačka bude izložena za integraciju API upravljanja. Nakon što je API Management konfigurisan, trebalo bi da premestite ovaj kod nazad u if izraz i ponovo rasporedite Veb API. Nikada ne ostavljajte krajnju tačku Svagger-a otvorenu u proizvodnom sistemu.

  14. U prozoru Terminal , pokrenite sledeću komandu da biste generisali kontroler BoilerParts iz klase modela BoilerPart i klase konteksta InventoryContext .

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

    Kontroler BoilerParts treba da bude kreiran u folderu Controllers .

    [! NAPOMENA] Linija terminator karakter, ^, je prepoznat samo od strane Vindovsa. Ako koristite Visual Studio kod na Linuks sistemu, umesto toga koristite znak. \

  15. Otvorite BoilerParts.cs fajl u folderu Controllers i pregledajte njegov sadržaj. Klasa BoilerPartsController izlaže sledeće metode REST:

    • GetBoilerParts(), koji vraća listu svih BoilerPart objekata iz baze podataka.
    • GetBoilerPart(long id), koji preuzima detalje o navedenom delu kotla.
    • PutBoilerPart(long id, BoilerPart boilerPart), koji ažurira deo kotla u bazi podataka sa detaljima u objektu BoilerPart navedenom kao parametar.
    • PostBoilerPart(BoilerPart boilerPart), koji stvara novi deo kotla.
    • DeleteBoilerPart(long id), koji uklanja navedeni deo kotla iz baze podataka.

    Belešku

    Aplikacija tehničara zahteva samo dve Get metode, ali ostali su korisni za aplikaciju za upravljanje inventarom na radnoj površini (nije pokriveno u ovom vodiču).

  16. Kompilujte i napravite Web API.

    dotnet build
    

Web API treba da se izgradi bez prijavljivanja grešaka ili upozorenja.

Primena Web API-ja u usluzi Azure: Upravljanje zalihama na terenu

Kata je primenila i testirala Web API, izvršavajući sledeće zadatke:

  1. Koristeći dodatak za Azure nalog u usluzi Visual Studio Code, prijavite se na Azure pretplatu.

  2. Iz prozora terminala u kodu Visual Studio kreirajte novu grupu resursa pod nazivom webapi_rg u pretplati na Azure. U sledećoj komandi zamenite <lokaciju> sa najbližim Azure regionom.

    az group create ^
        --name webapi_rg ^
        --location <location>
    
  3. Kreirajte plan usluge Azure App Service da biste obezbedili resurse za hosting Web API-ja.

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

    Belešku

    FKSNUMKS je besplatni SKU za App Service planove. Omogućava ograničenu propusnost i kapacitet i pogodan je samo u razvojne svrhe.

  4. Napravite Azure veb-aplikaciju pomoću App Service plana. Zamenite <ime> vebapp sa jedinstvenim imenom za veb aplikaciju.

    az webapp create ^
        --name <webapp name> ^
        --resource-group webapi_rg ^
        --plan webapi_plan
    
  5. U Kodu Visual Studio , uredite appSettings.json fajl, i dodajte isti string veze koji ste prethodno napisali u appSettings.Development.json fajl. Ne zaboravite da zamenite <ime> servera sa imenom SKL baze podataka servera koji ste kreirali da biste držali bazu podataka InventoriDB .

    {
        "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. U prozoru Terminal, pripremite Web API paket za primenu u usluzi Azure.

    dotnet publish -c Release -o ./publish
    

    Ova komanda čuva upakovane fajlove u folder koji se zove objavi.

  7. U Kodu Visual Studio kliknite desnim tasterom miša na fasciklu za objavljivanje , a zatim izaberite Primeni u Veb aplikaciju.

    Primena veb-aplikacije iz aplikacije VS Code.

  8. Izaberite ime veb aplikacije koju ste kreirali ranije u koraku 4 (<ime> vebapp). U sledećem primeru, veb aplikacija se zove mi-fieldengineer-vebapp.

    Izaberite veb-aplikaciju.

  9. Na promptu u dijalogu Visual Studio Kod izaberite Deploi da biste prihvatili upozorenje i rasporedili veb aplikaciju.

    Upozorenje o VS Code primeni.

  10. Uverite se da je veb-aplikacija uspešno primenjena, a zatim potražite veb-lokaciju.

    Dijalog za pronalaženje veb-lokacije u aplikaciji VS Code.

  11. Veb-lokacija će se otvoriti u novom prozoru pregledača, ali će prikazati grešku HTTP 404 (nije pronađeno). To je zato što su Veb API operacije dostupne preko api krajnje tačke, a ne korena veb sajta. Promenite URL u https://<ime vebapp-a>.azurewebsites.net/api/BoilerParts. Ovaj URI poziva metodu GetBoilerParts u kontroleru BoilerParts . Veb API treba da odgovori sa JSON dokumentom koji navodi sve delove kotla u InventoriDB bazi podataka.

    Lista delova prikazana u veb-pregledaču.

  12. Promenite URL u pretraživaču u https://<ime> vebapp.azurewebsites.net/swagger. Swagger API treba da se prikaže. Ovo je grafički korisnički interfejs koji programeru omogućava da verifikuje i testira svaku od operacija u Web API-ju. Takođe deluje kao korisno sredstvo za dokumentovanje.

    Swagger korisnički interfejs koji prikazuje listu operacija.

  13. Izaberite GET pored / api / BoilerParts / endpoint, a zatim izaberite Isprobajte. {id}

    Ekran „Isprobajte“ u Swagger korisničkom interfejsu

  14. U id polje unesite ID dela, a zatim izaberite Ekecute. Ova akcija poziva GetBoilerPart (long id) metod u kontroleru BoilerParts . Vratiće JSON dokument sa detaljima dela ili HTTP 404 grešku ako odgovarajući deo ne bude pronađen u bazi podataka.

    Odgovor u Swagger korisničkom interfejsu.

  15. Zatvorite veb-pregledač i vratite se u Visual Studio Code.

Izgradnja i primena Web API-ja: Baza znanja na terenu

Operacije baze znanja na terenu u Veb API-ju rade na tri tabele u bazi podataka KnovnDB : Saveti, BoilerParts i Inženjeri. Sledeća slika prikazuje relacije među ovim tabelama i kolonama koje sadrže.

Relacije između tabela baze znanja.

Kiana je usvojila sličan pristup za bazu podataka Field Knowledgebase koja je korišćena za bazu podataka Field Inventory Management i izvršila sledeće zadatke:

  1. Kreirajte klase C # modela koje odražavaju strukturu tabele Tips, BoilerParts i Engineers u bazi podataka KnovnovDB . Šifra svake od ovih klasa prikazana je u nastavku.

    Belešku

    Tabela BoilerParts u bazi podataka KnowledgeDB razlikuje se od tabele BoilerParts u bazi podataka InventoryDB . Da bi se izbegao sukob imena, klase modela za tabele u bazi podataka KnowledgeDB imaju prefiks 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; }
        }
    }
    

    Belešku

    Inženjer Id je niz, a ne broj. To je zato što postojeći sistemi koriste GUID-ove za utvrđivanje identiteta tehničara i drugih korisnika.

    // 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. Kreirajte još jednu klasu konteksta Entiti Framevork koju Veb API koristi za povezivanje sa bazom podataka KnowledgeDB .

    // 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. Izmenite appsettings. Development.json fajl za projekat i dodajte sledeći KnovledgDB string veze u odeljak ConnectionStrings . Zamenite <ime> servera sa imenom SKL baze podataka servera koji ste kreirali da biste držali bazu podataka KnovnovDB .

    {
        "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": {
            ...
            }
        }
    }
    

    Važno

    Samo za potrebe ovog vodiča, niska veze sadrži ID korisnika i lozinku za bazu podataka. U proizvodnom sistemu ove stavke nikada ne smete čuvati u čistom tekstu u datoteci za konfiguraciju.

  4. Izmenite Startup.cs fajl i, u metodi ConfigureServices , dodajte sledeće izjave.

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

    Druga naredba kontroliše način na koji se podaci serijalizuju kada se preuzmu. Neke klase modela imaju reference na druge klase modela, koje se pak mogu pozivati na dalje klase modela. Neke od ovih referenci mogu rezultirati rekurzivnim petljama (entitet A upućuje na entitet B, koji se vraća na entitet A, koji se ponovo poziva na entitet B i tako dalje). Opcija ReferenceLoopHandling izaziva serializator da ignoriše takve petlje u podacima, i vraća samo entitet i objekte na koje se odmah poziva, ali ne više.

  5. U prozoru terminala pokrenite sledeću komandu da biste generisali kontrolere iz klasa modela KnovBaseBoilerTip, KnovBaseBoilerPart i KnovBaseEngineer i kontekstne klase KnovnovBaseContext .

    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
    

    Sva tri kontrolera treba da budu kreirana u folderu Controllers .

  6. Izmenite KnowledgeBaseBoilerPartController.cs fajl. Ovaj fajl sadrži kod za kontroler KnovledgeBaseBoilerPart . Trebalo bi da prati isti obrazac kao i klasa BoilerPartsController kreirana ranije, izlažući REST metode koje omogućavaju klijentu da nabroji, upit, ubaci, ažurira i izbriše entitete. Dodajte sledeću metodu GetTipsForPart kontroleru.

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

    Ova metoda vraća sve savete iz baze znanja koji se odnose na navedeni deo. On upit tabelu Saveti u bazi podataka preko objekta KnowledgeBaseContext da pronađe ove informacije.

  7. Izmenite KnowledgeBaseEngineerController.cs fajl i dodajte sledeći metod u klasu KnowledgeBaseEngineerController .

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

    Metoda GetTipsForEngineer pronalazi sve savete za bazu znanja koje je objavio određeni inženjer.

  8. U prozoru terminala , kompajlirajte i izgradite Veb API.

    dotnet build
    

    Web API treba da se izgradi bez prijavljivanja grešaka ili upozorenja.

  9. Uredite appSettings.json datoteku i dodajte niz veze za bazu podataka KnovnovDB . Ovaj string treba da bude isti koji ste prethodno napisali u appSettings.Development.json fajl.

    {
        "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. U prozoru terminala , paketirajte Veb API spreman za primenu na Azure.

    dotnet publish -c Release -o ./publish
    
  11. U Kodu Visual Studio kliknite desnim tasterom miša na fasciklu za objavljivanje , a zatim izaberite Primeni u Veb aplikaciju. Primenite istu Azure veb-aplikaciju koju ste prethodno kreirali. Dozvolite čarobnjaku da zameni postojeću veb-aplikaciju novim kodom.

  12. Kada je primena završena, potražite na sajtu, ali promenite URL u pretraživaču u https://<vebapp ime>.azurewebsites.net/swagger. Operacije za kontrolere KnovledgeBaseBoilerPart, KnovledgeBaseEngineer i KnovldgeBaseTip treba da budu navedene pored postojećih operacija BoilerParts . Proverite da li operacije KnovledgeBaseBoilerPart uključuju GET operaciju za URI / api / KnovledgeBaseBoilerPart / / Tips , a operacije KnovledgeBaseEngineer uključuju{id}GEToperaciju za URI / api / KnovledgeBaseEngineer / / Tips .{id}

    Swagger korisnički interfejs sa novim operacijama.

Izgradnja i primena Web API-ja: Zakazivanje na terenu

Operacije zakazivanja polja koriste tabele Sastanci , ImenovanjaStatusi (ovo je jednostavna tabela za pretragu koja navodi važeće vrednosti statusa sastanka), Kupci i Inženjeri, prikazani na sledećoj slici. Ove tabele se čuvaju u bazi podataka SchedulesDB .

Relacije između zakazanih obaveza i tabela za zakazivanje.

Da bi kreirala Web API operacije za deo sistema za zakazivanje na terenu, Kata je izvršila sledeće zadatke:

  1. Kreirajte klase C # modela koje odražavaju strukturu tabele AppointmentStatus, Appointments , Customers i Engineersu bazi podataka SchedulesDB . Sledeći kôd prikazuje svaku od ovih klasa.

    Belešku

    Klasa modela za tabelu Inženjeri se zove ScheduleEngineer da bi se razlikovala od modela za tabelu Inženjeri u bazi podataka InventoryDB .

    // 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. Kreirajte klasu konteksta Entiti Framevork koju Veb API koristi za povezivanje sa bazom podataka SchedulesDB .

    // 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. Izmenite appsettings. Development.json datoteku za projekat i dodajte sledeći niz veze SchedulesDB u odeljak ConnectionStrings . Zamenite <ime> servera sa imenom SKL baze podataka servera koji ste kreirali da biste držali bazu podataka KnovnovDB .

    {
        "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. Izmenite Startup.cs fajl i u metodi ConfigureServices , dodajte sledeću izjavu.

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<InventoryContext>...;
    
        services.AddDbContex\<KnowledgeBaseContext>...;
    
        services.AddDbContext<ScheduleContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("SchedulesDB")));
    
        services.AddControllers().AddNewtonsoftJson(...);
    
        ...
    }
    
  5. U prozoru terminala pokrenite sledeću komandu da biste generisali kontrolere iz klasa modela Imenovanje, Customer i ScheduleEngineer i kontekstne klase ScheduleContext .

    Belešku

    Nemojte kreirati poseban kontroler za model AppointmentStatus .

    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. Izmenite AppointmentsController.cs fajl. U klasi AppointmentsController pronađite metodu GetAppointments . Izmenite povratnu izjavu , kao što je prikazano. Ova promena obezbeđuje da se informacije o klijentu, inženjeru i statusu imenovanja preuzmu kao deo operacije GET ; ova polja se odnose na druge entitete koji bi inače ostali nulti zbog lenog mehanizma učitavanja entitetskog okvira.

    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. U istoj datoteci modifikujte metodu GetAppointment(long id), kao što je prikazano.

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

    Ova verzija metode popunjava polja Customer, Engineer i AppointmentStatus sastanka kada se preuzme (lenji učitavanje bi ostavilo ova polja prazna u suprotnom).

  8. Pronađite metodu PutAppointment i zamenite je sledećim kodom. Ova verzija metode PutAppointment uzima polja u sastanku koje korisnik može da modifikuje u aplikaciji, a ne kompletan objekat imenovanja .

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

    Belešku

    Kao opšte pravilo, PUT operacije treba da menjaju samo podatke za koje korisnik treba da ima mogućnost ažuriranja, a ne nužno i svako polje u entitetu.

  9. Otvorite ScheduleEngineerController.cs datoteku i dodajte sledeću metodu GetScheduleEngineerAppointments u klasu ScheduleEngineerController .

    [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. Uredite CustomerController.cs datoteku i dodajte metode GetAppointments i GetNotes , kao što je prikazano, u klasu CustomerController .

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

    Metoda GetAppointments pronalazi sve sastanke za navedenog kupca. Metoda GetNotes preuzima sve beleške koje je tehničar napravio na prethodnim posetama kupcu.

  11. Uredite appSettings.json datoteku i dodajte niz veze za bazu podataka KnovnovDB . Ovaj string treba da bude isti koji ste prethodno napisali u appSettings.Development.json fajl.

    {
        "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. U prozoru terminala , kompajlirajte i izgradite Veb API.

    dotnet build
    

    Web API treba da se izgradi bez prijavljivanja grešaka ili upozorenja.

  13. U prozoru terminala , paketirajte Veb API spreman za primenu na Azure.

    dotnet publish -c Release -o ./publish
    
  14. U Kodu Visual Studio kliknite desnim tasterom miša na fasciklu za objavljivanje , a zatim izaberite Primeni u Veb aplikaciju. Primenite istu Azure veb-aplikaciju koju ste prethodno kreirali. Dozvolite čarobnjaku da zameni postojeću veb-aplikaciju novim kodom.

  15. Kada je primena završena, potražite na sajtu, ali promenite URL u pretraživaču u https://<vebapp ime>.azurewebsites.net/swagger. Proverite da li su operacije za Imenovanja, Kupac i ScheduleEngineer kontroleri su sada dostupni.

Web API je sada spreman za ugradnju u aplikaciju.