Ajastettujen Azure Functions -toimintojen testaaminen paikallisessa kehitysympäristössä tarjoaa mahdollisuuden tarkastella, kuinka toiminnot reagoivat erilaisiin HTTP-pyyntöihin ja ajastetun tapahtuman laukaisemiseen. Tämä prosessi on hyödyllinen, kun kehittäjä haluaa testata toimintojaan ennen tuotantoon siirtämistä tai vianetsinnän yhteydessä.

Yksi tärkeimmistä asioista, jotka tulee ymmärtää, on ajastetun toiminnon aktivoiminen ja sen manuaalinen laukaiseminen ilman, että odotetaan seuraavaa ajastetun tehtävän suoritusaikaa. Azure Functions tukee erilaisia tapahtumia, ja ajastetut funktiot voidaan määrittää käynnistymään tietyin aikarajoin, mutta niitä voidaan myös käskeä suoritettavaksi ohjelmallisesti, mikä helpottaa testausta ja vianetsintää.

Testausprosessin alussa on tärkeää käynnistää paikallinen ympäristö. Tämä tarkoittaa, että Northwind.AzureFunctions.Service -projekti tulee käynnistää. Jos käytät Visual Studio Codea, on varmistettava, että Azurite-laajennus on asennettu ja Azurite-palvelut käynnissä. Tämän jälkeen kehitysympäristössä näkyy kaksi toimintoja: NumbersToWordsFunction ja ScrapeAmazonFunction. Tällä hetkellä keskitymme erityisesti ajastetun ScrapeAmazonFunction-toiminnon testaamiseen.

Ensimmäinen askel on saada tietoa funktiosta. Tämä voidaan tehdä tekemällä HTTP GET -pyyntö seuraavasti: http://localhost:7071/admin/functions/ScrapeAmazonFunction. Tässä vaiheessa palautetaan JSON-dokumentti, joka sisältää tarvittavat tiedot ajastetusta toiminnosta. Tärkeää on kiinnittää huomiota "bindings" -kenttään, joka määrittelee, että kyseessä on timerTrigger ja "schedule", joka ilmaisee ajastetun tehtävän aikarajapohjan, kuten esimerkiksi 0 0 * * * * – joka tarkoittaa, että funktio suoritetaan joka tunti.

Toiminnon manuaalinen laukaisu on myös tärkeä testausvaihe. Kun lähetämme POST-pyynnön tyhjän JSON-dokumentin kanssa, funktio käynnistyy heti ilman, että ajastetta tarvitsisi odottaa. Tämä voi olla erityisen hyödyllistä, jos halutaan testata toiminnon nopeaa reaktiota tai tarkistaa, että se reagoi odotetulla tavalla.

Kun tarkastellaan funktioiden toimintalogiikkaa ja ajastusta, on tärkeää huomata, että kun palvelu käynnistetään uudelleen, ja odotetaan yli tunti, toiminto voi silti laukaista, jos se on "myöhässä" aiemmasta aikarajasta. Tämä tapahtuu, koska ajastetun toiminnon aikarajojen hallinta on joustava, ja se suoritetaan seuraavalla mahdollisella ajankohdalla, jos edellinen ajankohta on jäänyt väliin.

Vianetsinnissä kannattaa kiinnittää huomiota myös virheilmoituksiin. Esimerkiksi jos tyhjän JSON-dokumentin lähettäminen POST-pyynnön mukana epäonnistuu, tulee palautetta HTTP 400 Bad Request -virheestä, joka ilmoittaa, että tyhjä dokumentti on vaadittu. Tämä auttaa kehittäjää tunnistamaan, missä osassa pyyntöä ongelma piilee.

Kun palvelu toimii oikein ja ajastetut toiminnot käynnistyvät säännöllisesti, on mahdollista tarkastella seuraavia ajankohtia, jolloin funktio suoritetaan. Tällöin voidaan nähdä tulevien suoritusten ajat UTC-aikavyöhykkeellä, mikä on tärkeää, jos palvelun toiminta pitää olla tarkkaa ja luotettavaa, erityisesti globaalissa ympäristössä.

Azure Functionsin avulla kehittäjät voivat helposti luoda palvelimettomia nano-palveluja, jotka suorittavat pienimuotoisia tehtäviä, kuten tietojen keräämistä ja käsittelyä ajastettuna. Kuitenkin on tärkeää muistaa, että ajastetut funktiot ja niiden laukaisevat mekanismit eivät ole ainoastaan ajankohtaisia, vaan niiden täsmällisyys ja luotettavuus voivat olla riippuvaisia monista tekijöistä, kuten ympäristön tilasta ja virheiden käsittelystä.

Kuinka yhdistää ja käyttää ADO.NET:ia SQL Serverin kanssa

Kun käytetään ADO.NET:ia tietokannan kanssa, on tärkeää ymmärtää, miten yhteyden luominen ja tiedon käsittely toimii tehokkaasti. Yhteyden muodostaminen SQL Serveriin on ensimmäinen askel, ja se voidaan tehdä useilla eri tavoilla riippuen siitä, käytetäänkö Azure SQL -tietokantaa, Azure SQL Edgeä vai paikallista SQL Serveriä. Esimerkiksi, jos käytät Azure SQL -tietokantaa, sinun tulee antaa käyttäjätunnus ja salasana, kun taas paikallisessa SQL Serverissä voit käyttää Windowsin integroituja turvatoimia, jolloin salasanaa ei tarvita.

Kun yhteys on luotu, voidaan SQL-kyselyjä suorittaa ja tietoja käsitellä. ADO.NET tarjoaa tehokkaita työkaluja, kuten SqlCommand ja SqlDataReader, joiden avulla voidaan suorittaa SQL-kyselyitä ja lukea tuloksia ohjelmallisesti. Esimerkiksi, jos haluat valita tuotteen ID:n, nimen ja hinnan Products-taulusta, voit käyttää seuraavaa koodia:

csharp
SqlCommand cmd = connection.CreateCommand();
cmd.CommandType = CommandType.Text; cmd.CommandText = "SELECT ProductId, ProductName, UnitPrice FROM Products"; SqlDataReader r = cmd.ExecuteReader(); while (r.Read()) { WriteLine("| {0,5} | {1,-35} | {2,8:C} |", r.GetInt32("ProductId"), r.GetString("ProductName"), r.GetDecimal("UnitPrice")); } r.Close();

Tässä esimerkissä suoritetaan yksinkertainen SQL-kysely, joka palauttaa tuotteen ID:n, nimen ja hinnan. Tulokset tulostetaan konsoliin, ja hinta muotoillaan käyttäen nykyistä valuutan formaattia, joka perustuu ohjelman ympäristöön.

Yksi hyödyllinen ominaisuus ADO.NET:issa on mahdollisuus käyttää parametrejä SQL-kyselyissä. Tämä parantaa sekä turvallisuutta että suorituskykyä. Esimerkiksi jos haluat suodattaa tuloksia tietyn hinnan perusteella, voit käyttää parametrisoitua kyselyä:

csharp
string? priceText = ReadLine();
if (!decimal.TryParse(priceText, out decimal price)) { WriteLine("Syötä kelvollinen yksikköhinta."); return; } SqlCommand cmd = connection.CreateCommand(); cmd.CommandType = CommandType.Text; cmd.CommandText = "SELECT ProductId, ProductName, UnitPrice FROM Products WHERE UnitPrice > @price"; cmd.Parameters.AddWithValue("price", price);

Tässä esimerkissä käyttäjältä pyydetään syöttämään hinta, ja SQL-kysely suodattaa tuotteet, joiden hinta on suurempi kuin syötetty arvo. Tämä lähestymistapa varmistaa, että koodissa ei ole SQL-injektioita ja se parantaa suorituskykyä, koska kyselyt voidaan optimoida paremmin.

Tämän lisäksi ADO.NET tukee asynkronista ohjelmointia, mikä voi parantaa sovelluksen reagointikykyä, erityisesti monisäikeisissä ympäristöissä. Asynkronisten metodien avulla voit estää sovelluksen jäätymisen esimerkiksi käyttäjäliittymän toiminnassa tai verkkosivustolla. Esimerkiksi yhteyden avaaminen ja tietojen lukeminen voidaan tehdä asynkronisesti seuraavasti:

csharp
await connection.OpenAsync();
SqlDataReader r = await cmd.ExecuteReaderAsync(); while (await r.ReadAsync()) { WriteLine("| {0,5} | {1,-35} | {2,8:C} |", await r.GetFieldValueAsync("ProductId"), await r.GetFieldValueAsync("ProductName"), await r.GetFieldValueAsync("UnitPrice")); } await r.CloseAsync(); await connection.CloseAsync();

Asynkronisten operaatioiden käyttö ei muuta lopputuloksia, mutta se parantaa huomattavasti suorituskykyä ja tekee sovelluksesta responsiivisemman. Tämä on erityisen tärkeää, kun käsitellään pitkiä yhteyksiä, suuria tietomääriä tai monimutkaisia käyttäjäliittymiä.

Jos sovellus tarvitsee suorittaa sama kysely useita kertoja, on hyvä käyttää tallennettuja proseduuria (stored procedure), joka voidaan esikääntää ja optimoida. Tallennetut proseduurit mahdollistavat parametrien käytön ja voivat parantaa suorituskykyä, erityisesti silloin, kun kyselyt ovat monimutkaisempia tai toistuvia. Esimerkiksi voit määrittää tallennetun proseduurin, joka ottaa vastaan minimihinnan ja palauttaa tuotteet, joiden hinta on yli tämän arvon:

sql
CREATE PROCEDURE GetExpensiveProducts @MinPrice DECIMAL, @RowCount INT OUTPUT AS BEGIN SELECT ProductId, ProductName, UnitPrice FROM Products WHERE UnitPrice > @MinPrice;
SET @RowCount = (SELECT COUNT(*) FROM Products WHERE UnitPrice > @MinPrice);
END

Tällöin voit kutsua tätä proseduuria ADO.NET:in avulla ja saada tulokset sekä myös tietoa siitä, kuinka monta riviä palautettiin.

Erityisesti, kun työskentelet SQL Serverin tai muiden relaatiotietokantojen kanssa, on tärkeää huomioida muutama keskeinen seikka:

  • Yhteyksien hallinta on oleellista, sillä pitkittyneet yhteydet voivat estää sovelluksen suorituskykyä. Käyttämällä using-lauseita voit varmistaa, että yhteydet suljetaan oikein, kun niitä ei enää tarvita.

  • ADO.NET tarjoaa useita eri komento- ja lukijatyyppejä, jotka voivat parantaa suorituskykyä, kuten SqlDataReader ja SqlCommand. Oikean työkalun valinta voi vähentää koodin monimutkaisuutta ja parantaa resurssien käyttöä.

  • Asynkronisuus on kriittinen osa moderneja sovelluksia, ja sen käyttö ei rajoitu vain käyttöliittymien sujuvuuteen, vaan myös taustaprosessien ja tietokantayhteyksien optimointiin.

Kuinka hallita sisäkkäisiä ja rinnakkaistehtäviä C#:ssa ja varmistaa niiden synkronointi

Ohjelmoinnissa, erityisesti rinnakkaisuus- ja moniajo-tilanteissa, on usein tarpeen hallita useita tehtäviä samanaikaisesti. C#:ssa tämä voidaan toteuttaa käyttämällä Task-luokkaa, joka mahdollistaa asynkronisten tehtävien suorittamisen taustalla ilman, että pääohjelman suoritusta keskeytettäisiin. Näissä tilanteissa on kuitenkin tärkeää ymmärtää, kuinka tehtävien käynnistys ja niiden välinen synkronointi toimii, jotta saadaan aikaan tehokas ja virheetön suoritus.

Esimerkiksi, jos haluamme käynnistää kaksi tehtävää, jotka toimivat toistensa sisällä, voimme käyttää seuraavaa rakennetta:

csharp
static void OuterMethod() { TaskTitle("Outer method starting..."); Task innerTask = Task.Factory.StartNew(InnerMethod); TaskTitle("Outer method finished."); } static void InnerMethod() { TaskTitle("Inner method starting..."); Thread.Sleep(2000); TaskTitle("Inner method finished."); }

Tässä esimerkissä OuterMethod käynnistää InnerMethod-tehtävän. Vaikka ulompi tehtävä (OuterMethod) loppuu nopeasti, sisempi tehtävä voi jatkaa suoritustaan sen jälkeen, kun ulompi on ehtinyt päättyä. Tällöin konsolissa voidaan nähdä seuraava tulostus:

sql
Outer method starting... Inner method starting... Outer method finished. Console app is stopping.

Tärkeä huomio tässä on se, että ulompi tehtävä voi loppua ennen sisemmän tehtävän valmistumista. Tämä ei kuitenkaan tarkoita, että konsolipohjainen ohjelma päättyisi ennen sisemmän tehtävän suorittamista. Jos kuitenkin haluamme, että sisemmän tehtävän on aina suoritettava ennen ulomman tehtävän päättymistä, voimme käyttää TaskCreationOptions.AttachedToParent-asetusta, joka liittää sisemmän tehtävän ulomman tehtävän elinkaaren mukaan. Tämä varmistaa, että sisempi tehtävä suoritetaan ja valmistuu ennen ulomman tehtävän päättymistä:

csharp
Task innerTask = Task.Factory.StartNew(InnerMethod, TaskCreationOptions.AttachedToParent);

Kun tätä vaihtoehtoa käytetään, tulostus näyttää tältä:

sql
Outer method starting... Inner method starting... Outer method finished. Inner method finished. Console app is stopping.

Tämä koodi varmistaa, että sisemmän tehtävän suorittaminen on täysin valmis ennen ulomman tehtävän päättymistä, ja siten ohjelma ei pääty ennen kuin molemmat tehtävät on suoritettu.

Tehtävien pakkaaminen muiden objektien ympärille

Toisinaan saatamme haluta suorittaa asynkronisen metodin, mutta metodin palauttama tulos ei ole itse asiassa tehtävä. Tällöin voimme "pakata" tuloksen onnistuneesti suoritettuun tehtävään käyttämällä Task.FromResult-metodia, joka palauttaa tehdyn tuloksen osaksi asynkronista tehtävää:

csharp
public static Task IsValidXmlTagAsync(this string input) { if (input == null) {
return Task.FromException(new ArgumentNullException($"Missing {nameof(input)} parameter"));
}
if (input.Length == 0) { return Task.FromException(new ArgumentException($"{nameof(input)} parameter is empty.")); } return Task.FromResult(Regex.IsMatch(input, @"^<([a-z]+)([^<]+)*(?:>(.*)<\/\1>|\s+\/>)$")); }

Tässä esimerkissä metodi palauttaa tehtävän, jonka tuloksena on joko virhe tai onnistunut tarkistus. Tällöin ohjelma voi toimia synkronisesti, mutta säilyttää asynkronisen rajapinnan.

Jos metodi itsessään on synkroninen, mutta sen tulokset halutaan palauttaa asynkronisesti, voidaan käyttää Task.CompletedTask-metodia, joka palauttaa jo suoritettu tehtävän ilman varsinaista työnkulkua:

csharp
public Task DeleteCustomerAsync()
{ // ... return Task.CompletedTask; }

Tämä lähestymistapa on erityisen hyödyllinen, kun halutaan toteuttaa asynkroninen rajapinta, mutta itse toteutus voi olla synkroninen.

Rinnakkaisten tehtävien synkronointi

Monet ohjelmat suorittavat useita tehtäviä samanaikaisesti, mutta useiden säikeiden käsittely voi johtaa ongelmiin, kuten useiden säikeiden pääsy samaan resurssiin yhtä aikaa. Tällöin täytyy käyttää synkronointimekanismeja estämään resurssien samanaikainen käyttö.

Yksi yksinkertaisimmista tavoista hallita tällaista tilannetta on käyttää "lippua" tai "konsolia" (vrt. William Goldingin Kärpästen herra -romaani), joka toimii lukkona ja estää toisia säikeitä pääsemästä ja manipuloimasta jaettua resurssia yhtä aikaa. Näin yksittäinen säie voi käyttää resurssia vain silloin, kun se on "omistanut" lippunsa.

Esimerkiksi seuraavassa koodissa synkronoimme pääsyn jaetulle resurssille:

csharp
static class SharedObjects
{ public static string? Message; // a shared resource } partial class Program { static void MethodA() { for (int i = 0; i < 5; i++) { Thread.Sleep(Random.Shared.Next(2000)); SharedObjects.Message += "A"; Write("."); } } static void MethodB() { for (int i = 0; i < 5; i++) { Thread.Sleep(Random.Shared.Next(2000)); SharedObjects.Message += "B"; Write("."); } } }

Tässä ohjelmassa kaksi erillistä metodia (MethodA ja MethodB) manipuloivat yhteistä Message-resurssia. Ne odottavat satunnaisen ajan ennen kuin lisäävät kirjaimen resurssiin. Koska useat säikeet voivat manipuloida tätä resurssia samanaikaisesti, synkronointi on välttämätöntä, jotta ei tapahdu virheitä tai datan ylikirjoituksia.

Tällöin voidaan käyttää välineitä, kuten Monitor-luokkaa tai Interlocked-luokkaa, jotka mahdollistavat synkronoidun pääsyn jaettuihin resursseihin. Näiden työkalujen avulla voidaan hallita resurssin lukitsemista ja varmistaa, että vain yksi säie käyttää resurssia kerrallaan.

On tärkeää muistaa, että synkronointi ei ole pelkästään teoreettinen käsite, vaan käytännön työkalu, jota tulee käyttää tarkasti ja oikein. Liiallinen synkronointi voi estää ohjelman suorituksen tehokkuuden, mutta oikea käyttö takaa turvallisuuden ja oikeellisuuden rinnakkaisessa ohjelmoinnissa.

Miksi salaus ja hajautus ovat keskeisiä tietoturvassa ja miten niitä voidaan käyttää käytännössä?

Tietoturva on olennainen osa ohjelmistojen ja sovellusten suunnittelua, sillä se suojaa käyttäjien yksityisyyttä ja varmistaa, että tiedot pysyvät luottamuksellisina. Salaus ja hajautus ovat kaksi keskeistä tekniikkaa, joita käytetään tietojen suojaamiseksi. Tässä käsitellään käytännön esimerkkiä, jossa salauksen ja hajautuksen toteutusta tarkastellaan C#-ohjelmointikielen ja .NET:n kontekstissa.

Salauksen ja hajautuksen käyttöön liittyy monia tärkeitä näkökohtia. Esimerkiksi AES-salauksen (Advanced Encryption Standard) käyttö on yleinen tapa suojata dataa. AES tukee eri avaimen pituuksia, kuten 128, 192 ja 256 bittiä, mutta turvallisuuden kannalta suositellaan yleensä pidemmän, 256-bittisen avaimen käyttöä. Salauksen aikana on tärkeää valita oikea tila (mode), kuten CBC (Cipher Block Chaining), ja oikea täytealgoritmi (padding), kuten PKCS7, joka estää mahdolliset tietovuodot.

Salauksen ja purkamisen prosessi alkaa salausavaimen ja IV:n (Initial Vector) luomisella. Tämä tehdään usein käyttäen PBKDF2-algoritmia, joka johdattaa salauksen avaimen ja IV:n käytettävissä olevista salasanan ja suolan tiedoista. Tämä menetelmä on tehokas, mutta sen suorituskyvyn optimoiminen on tärkeää. Esimerkiksi, vaikka iteraatiomäärä voidaan asettaa korkeaksi (esim. 150 000 kertaa), on tärkeää, että avaimen ja IV:n luominen kestää vähintään 100 millisekuntia, jotta suojaustaso on riittävä.

Tässä esimerkissä käytetty C#-koodi luo salauksen ja purkamisen mekanismin, jossa salasanan ja suolan avulla johdetaan avaimet ja IV:t, joita käytetään AES-algoritmissa. Ennen kuin tieto voidaan salata, se muunnetaan tavuiksi (bytes) ja sitten kirjoitetaan muistivirtaukseen (MemoryStream), jossa se salataan luodulla muunnosobjektilla (ICryptoTransform). Tietojen purkaminen tapahtuu päinvastoin: salattu teksti muunnetaan tavuiksi, ja purkamisprosessi palauttaa alkuperäisen selkotekstin.

On myös tärkeää huomioida, että salasanan kovakoodaus lähdekoodiin ei ole suositeltavaa. Vaikka sovellus on käännetty, salasana on silti luettavissa käännetystä ohjelmasta, mikä voi altistaa sen tietomurroille. Siksi on parempi pyytää salasana käyttäjältä ajonaikaisesti eikä tallentaa sitä lähdekoodiin tai muuhun haavoittuvaan paikkaan.

Toinen olennainen huomio on hajautusalgoritmien valinta. Hajautusalgoritmit, kuten SHA256, SHA512 ja vanhemmat MD5 ja SHA1, ovat käytettävissä tiedon tiivistämiseen, mutta niillä on eri tasoja turvallisuutta. Esimerkiksi MD5 ja SHA1 ovat tunnettuja heikkouksistaan, ja niiden käyttöä suositellaan välttämään, sillä niiden tietoturva on kyseenalaistettu. SHA256 on yleisesti ottaen turvallinen vaihtoehto ja tarjoaa riittävän suojan useimmissa sovelluksissa.

Kun käytetään hajautusta, on tärkeää ymmärtää kaksi keskeistä käsitettä: törmäysresistenssi ja alkuperäiskuvan resistenssi. Törmäysresistenssi tarkoittaa sitä, kuinka vaikeaa on löytää kahta erilaista syötettä, jotka tuottavat saman hajautusarvon. Alkuperäiskuvan resistenssi puolestaan viittaa siihen, kuinka vaikeaa on löytää syöte, joka tuottaa tietyn hajautusarvon. Tämän vuoksi on suositeltavaa käyttää hajautusalgoritmeja, jotka tarjoavat vahvan suojan näitä hyökkäyksiä vastaan.

Hyvän käytännön mukaan on tärkeää pitää kirjaa salausvalinnoista, kuten käytetystä salausalgoritmista, täytealgoritmista ja iteraatioiden määrästä, koska tämä helpottaa mahdollisia tulevia päivityksiä, kuten salausalgoritmien tai avaimen koon parantamista. Tätä käytäntöä kutsutaan kryptografiseksi joustavuudeksi (cryptographic agility).

Tietoturvassa on tärkeää myös testata käytettyjä salausmekanismeja ja varmistaa, että salaus ja purkaminen toimivat oikein. Esimerkiksi ohjelman suorittamisen aikana käyttäjältä voidaan pyytää salasanan ja viestin syöttämistä, ja ohjelma voi sitten salata ja purkaa tekstin. Jos salasana on väärä purkamisen yhteydessä, ohjelma voi heittää virheen, joka estää väärän salasanan käytön.

Lopuksi on tärkeää muistaa, että salaus ja hajautus ovat vain osa laajempaa tietoturvapolitiikkaa. Hyvin suunniteltu ja toteutettu salaus voi estää tietomurtoja, mutta se ei yksinään riitä suojaamaan järjestelmiä. On tärkeää huolehtia myös muista tietoturvatoimista, kuten pääsynhallinnasta, haavoittuvuuksien hallinnasta ja varmuuskopioinnista.

Miten luoda GraphQL-palvelu ASP.NET Corella: Käytännön opas

GraphQL on kyselykieli, joka antaa käyttäjälle mahdollisuuden kysyä vain tarvitsemiaan tietoja yhdestä pyynnöstä. Tämä on erityisen kätevää monimutkaisissa sovelluksissa, joissa on suuri määrä tiedonlähteitä, ja se tarjoaa huomattavaa joustavuutta verrattuna perinteisiin REST-rajapintoihin. Hot Chocolate -kirjasto on suosittu GraphQL-ympäristö .NET-maailmassa, ja tässä käsitellään, miten voit luoda GraphQL-palvelun ASP.NET Corella käyttämällä tätä kirjastoa.

Aluksi on tärkeää huomata, että GraphQL:lle ei ole olemassa valmista dotnet new -projektimallia, joten meidän on aloitettava tyhjästä. ASP.NET Core Empty -projekti on paras vaihtoehto aloitusmalliksi. Vaikka GraphQL ei ole sidottu HTTP:hen, on järkevää käyttää web-palvelinta palvelun isännöimiseen, koska se tarjoaa tutut työkalut ja helpottaa alkuun pääsemistä.

Ensimmäinen askel on luoda tyhjä ASP.NET Core -projekti Visual Studiossa tai haluamassasi koodieditorissa. Luo uusi projekti valitsemalla ASP.NET Core Empty -projekti ja määrittämällä seuraavat asetukset:

  • Projektin nimi: Northwind.GraphQL

  • Autentikointityyppi: Ei asetettu

  • HTTPS-tuki: Valittuna

  • Docker-tuki: Ei valittu

  • OpenAPI-tuki: Ei valittu

Kun projekti on luotu, lisää seuraavaksi tarvittavat paketit GraphQL:n tukemiseen. Hot Chocolate on tehokas GraphQL-kirjasto, joka toimii hyvin ASP.NET Coren kanssa, ja voit lisätä sen NuGet-paketin avulla. Suosittelen käymään seuraavassa linkissä ja lisäämään uusimman version: HotChocolate.AspNetCore.

Kun paketit on lisätty, siirry launchSettings.json-tiedostoon ja muokkaa palvelimen portteja seuraavasti:

json
"profiles": {
"http": { "commandName": "Project", "dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "graphql", "applicationUrl": "http://localhost:5112", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "https": { "commandName": "Project", "dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "graphql", "applicationUrl": "https://localhost:5111;http://localhost:5112", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } }

Nyt olet valmis määrittämään GraphQL-palvelun käyttämään luomaasi palvelinporttia ja käynnistämään sen.

Seuraava askel on luoda GraphQL-skeema. Tämä on olennainen osa GraphQL-palvelua, sillä sen avulla määritellään, mitä tietoja asiakas voi pyytää. Esimerkiksi, jos haluamme luoda yksinkertaisen "Hello, World!" -kyselyn, meidän tulee ensin luoda Query-luokka, joka määrittelee kyselyt, joita palvelu tukee:

csharp
namespace Northwind.GraphQL; public class Query {
public string GetGreeting() => "Hello, World!";
}

Tämän jälkeen lisäämme Query-luokan ASP.NET Core -projektin alustusosaan, jotta GraphQL-tuki otetaan käyttöön:

csharp
builder.Services .AddGraphQLServer() .AddQueryType<Query>();

Nyt, kun palvelu on määritelty ja käynnissä, voit käyttää BananaCakePop-käyttöliittymää testataksesi GraphQL-kyselyjä. Tämä työkalu mahdollistaa skeeman selaamisen ja kyselyjen suorittamisen helposti selaimessa. Kun napsautat "Browse schema", voit tarkistaa, että skeemassa on vain yksi kenttä: greeting, joka palauttaa merkkijonon "Hello, World!".

Kun määrittely on valmis, voidaan kirjoittaa ja suorittaa GraphQL-kysely. Voit tehdä tämän BananaCakePopissa, jossa saat autokomplettivihjeitä kirjoittaessasi kyselyä. Esimerkiksi seuraava kysely palauttaa "Hello, World!" -viestin:

graphql
{ greeting }

Kyselyjen nimeäminen on myös mahdollista. Esimerkiksi, jos haluamme luoda nimettyjä kyselyjä, voimme tehdä sen seuraavasti:

graphql
query GreetingQuery {
greeting }

Tämä on erityisen kätevää, kun käytetään GraphQL:ää pilvipalveluissa, kuten Microsoft Azure, ja halutaan seurata kyselyjen ja vastausten historiaa telemetrian avulla.

On myös tärkeää ymmärtää GraphQL-kenttien nimeämiskäytännöt. GraphQL:n kenttä nimetään yleensä pienellä alkukirjaimella (camelCase), vaikka C#-menetelmät noudattavat TitleCase-mallia. Esimerkiksi, jos lisäämme Farewell- ja RollTheDie-menetelmät Query-luokkaan:

csharp
public string Farewell() => "Ciao! Ciao!";
public int RollTheDie() => Random.Shared.Next(1, 7);

Kun palvelu on käynnissä, päivittyy myös skeema, ja voidaan lisätä kyselyjä, jotka pyytävät tietoja esimerkiksi noppapelin tuloksista:

graphql
query GetRandomNumber {
rollTheDie }

Tässä vaiheessa voit nähdä, että kysely tuottaa satunnaisen luvun välillä 1–6, ja suoritetut kyselyt jäävät näkyville käyttämääsi käyttöliittymään.

Kun palvelu on määritelty ja toiminnassa, on tärkeää huomata, että GraphQL:n vahvuus piilee sen kyvyssä yhdistää useita tietolähteitä ja yhdistää ne yhdeksi kyselyksi. Tämä tarkoittaa, että voit käyttää GraphQL:ää laajasti monimutkaisissa sovelluksissa, joissa on useita API-rajapintoja ja tietokantoja.