Reaaliaikainen tiedonsiirto on yksi moderneimpia verkkopalveluiden piirteitä, ja se mahdollistaa tiedon siirtämisen palvelimelta asiakkaille lähes välittömästi. SignalR on yksi tehokkaimmista työkaluista, joka tarjoaa helpon tavan toteuttaa reaaliaikaisia ominaisuuksia .NET-sovelluksissa. Tässä käsitellään, kuinka luoda asiakasohjelma, joka vastaanottaa ja lähettää reaaliaikaisia tietoja SignalR:n avulla.

Ensimmäinen askel on luoda SignalR-yhteys. Käytämme tässä esimerkissä .NET-ympäristössä rakennettua asiakasohjelmaa, joka vastaanottaa pörssikurssitietoja reaaliaikaisesti ja lähettää samalla tietoja palvelimelle. Tämä esimerkki on rakennettu niin, että se tukee asynkronista tiedonsiirtoa ja mahdollistaa molempiin suuntiin tapahtuvan reaaliaikaisen tiedon lähettämisen ja vastaanottamisen.

Asiakasohjelma toimii niin, että se ensin ottaa yhteyden SignalR-hubiin. Yhteys muodostetaan määrittämällä HubConnection-olio ja määrittelemällä palvelin, johon ollaan yhteydessä. Esimerkiksi koodissa HubConnection hubConnection = new HubConnectionBuilder().WithUrl("https://localhost:5131/stockprice").Build(); yhteys tehdään palvelimeen, joka tarjoaa pörssihintatietoja.

Kun yhteys on muodostettu, asiakasohjelma voi alkaa vastaanottamaan reaaliaikaisia päivityksiä, jotka saapuvat palvelimelta. Tietoja vastaanotetaan asynkronisesti, mikä tarkoittaa, että asiakas voi tehdä muita toimintoja samalla, kun se odottaa uutta tietoa. Esimerkissä tämä toteutetaan käyttämällä IAsyncEnumerable, joka mahdollistaa tietojen vastaanottamisen yhtä aikaa useista lähteistä ilman, että käyttäjän tarvitsee odottaa, että kaikki tiedot ovat valmiita.

Tietojen vastaanottamisen ohella asiakasohjelma voi lähettää myös omia tietojaan takaisin palvelimelle. Esimerkissä asiakasohjelma lähettää satunnaisesti luotuja osakekoodeja palvelimelle. Tietojen lähettäminen tapahtuu käyttämällä SendAsync-metodia, joka lähettää tiedot palvelimelle asynkronisesti.

SignalR:n avulla reaaliaikaisen tiedonsiirron toteuttaminen on tehokasta ja skaalautuvaa. SignalR huolehtii yhteyksien hallinnasta, ja asiakas voi keskeyttää yhteyden milloin tahansa peruutuskomennolla, mikä tehdään koodissa cts.Cancel();. Tämä mahdollistaa joustavan ja interaktiivisen käyttäjäkokemuksen, jossa asiakas voi itse hallita, mitä tietoja vastaanotetaan ja milloin tiedonsiirto lopetetaan.

Kun asiakasohjelma vastaanottaa pörssihintatietoja, se voi näyttää ne käyttäjälle reaaliaikaisesti. Tietojen päivitys tapahtuu säännöllisin väliajoin, esimerkiksi 4 sekunnin välein. Näin käyttäjä saa jatkuvasti ajantasaisia tietoja ilman, että hänen tarvitsee itse pyytää niitä. Tämä tekee sovelluksesta erittäin käyttäjäystävällisen ja reagoivan.

Erityisesti pörssikurssitietojen kaltaisten sovellusten kohdalla reaaliaikainen tiedonsiirto on erityisen tärkeää. Se mahdollistaa, että käyttäjät voivat tehdä päätöksiä välittömästi saatavilla olevan tiedon perusteella. Esimerkiksi, jos osakkeen hinta nousee tai laskee nopeasti, käyttäjä voi reagoida tähän heti, mikä on ratkaisevaa monille sijoittajille.

SignalR:llä on monia etuja, kuten se, että se tukee monia erilaisia kuljetusmekanismeja, kuten WebSocket- ja Long Polling -tekniikoita. WebSocket on yleisesti ottaen suosituin, koska se tarjoaa vakaan ja tehokkaan yhteyden, mutta SignalR osaa automaattisesti valita parhaan mahdollisen kuljetusmekanismin asiakkaan ja palvelimen välille.

Yksi tärkeimmistä asioista, joka on hyvä huomioida, on, että SignalR:llä luotu yhteys voi olla epävakaa tietyissä olosuhteissa, kuten verkkoyhteyksien heikentyessä. Tässä tapauksessa SignalR yrittää automaattisesti muodostaa yhteyden uudelleen, mutta on hyvä varautua siihen, että yhteyden menetys saattaa vaikuttaa käyttäjäkokemukseen. Tämän vuoksi on tärkeää, että ohjelma käsittelee mahdolliset virheet ja yhteyksien katkeamiset asianmukaisesti.

Yksi käytännön huomio liittyy myös peruutusmekanismien käyttöön. Kun asiakas ei enää halua vastaanottaa päivityksiä, on tärkeää, että tämä voidaan tehdä helposti ja selkeästi. Esimerkissä käyttäjä voi painaa "Y" peruuttaakseen päivitykset, mikä pysäyttää SignalR:n tiedonsiirron. Tämä on tärkeää erityisesti silloin, kun tiedonsiirto saattaa olla jatkuvaa ja käyttäjä ei halua enää vastaanottaa sitä.

Endtext

Miten luoda ja testata Azure Functions -projekti C#:lla

Azure Functions on palvelimettomien sovellusten kehittämiseen tarkoitettu pilvipalvelu, joka mahdollistaa koodin suorittamisen ilman tarvetta huolehtia infrastruktuurista. Sen avulla voi luoda pieniä, itsenäisiä palveluja, joita kutsutaan funktioiksi. Tässä osiossa tarkastelemme, kuinka luodaan yksinkertainen Azure Functions -projekti C#:lla ja testataan sen toimintaa paikallisesti.

Aluksi on tärkeää huomioida, että funktioita voidaan kehittää useilla eri työkaluilla, kuten Visual Studio Code tai komentoriviliittymä (CLI). Tässä esimerkissä käymme läpi vaiheet Visual Studio Coden avulla, mutta tarjoamme myös vaihtoehdon CLI:n käyttöön.

Projektin luominen Visual Studio Codessa

  1. Avaa Visual Studio Code ja sulje kaikki aiemmat työtilat. Tämän jälkeen valitse "View" ja "Command Palette", ja kirjoita siihen "azure f". Valitse komennot, jotka liittyvät Azure Functions -projektiin.

  2. Valitse "Azure Functions: Create New Project…" ja määritä kansio, johon projekti tallennetaan, kuten "Northwind.AzureFunctions.Service".

  3. Seuraavaksi sinulta kysytään kielen valinta, valitse C#. Sitten valitse .NET runtime -versio, kuten .NET 6.

  4. Seuraavaksi määritetään projektin ensimmäinen funktio, joka vastaa HTTP-pyyntöihin. Tällöin valitaan "HTTP trigger", joka mahdollistaa funktiosi käytön HTTP-pyyntöjen kautta.

  5. Anna funktiolle nimi, kuten "NumbersToWordsFunction" ja määritä sen namespace, esimerkiksi "Northwind.AzureFunctions.Service".

  6. Määritä valtuustaso (authorization level) "Anonymous", jolloin funktio voidaan kutsua ilman erityisiä oikeuksia.

  7. Nyt voit sulkea Visual Studio Coden ja avata Chapter14-työtilan, jossa olet valmis jatkamaan seuraavaan vaiheeseen.

Projektin luominen komentoriviltä (CLI)

Jos haluat käyttää komentoriviä, voit luoda projektin seuraavasti:

  1. Luo kansio "Chapter14" ja sen alle alikansio "Northwind.AzureFunctions.Service".

  2. Avaa komentoriviliittymä ja siirry "Northwind.AzureFunctions.Service" -kansioon. Käytä seuraavaa komentoa luodaksesi Azure Functions -projekti:

    csharp
    func init --csharp
  3. Luo uusi funktio HTTP triggerillä, joka voidaan kutsua anonyymisti:

    cpp
    func new --name NumbersToWordsFunction --template "HTTP trigger" --authlevel "anonymous"
  4. Voit käynnistää funktion paikallisesti komennolla:

    wasm
    func start

Jos "func"-komento ei ole tunnistettu, varmista, että Azure Functions Core Tools on asennettu, ja asenna se tarvittaessa.

Projektin rakenteen tarkastelu

Kun Azure Functions -projekti on luotu, on tärkeää ymmärtää, mitä se sisältää. Projektitiedostossa näkyy muun muassa käytettävät paketteja ja Azure Functions -version tiedot.

  • "host.json" -tiedostossa voidaan määrittää sovelluksen lokitustiedot, kuten Application Insightsin käyttö. Tässä esimerkissä se on otettu käyttöön, mutta pyyntötyypit on jätetty pois.

  • "local.settings.json" -tiedostossa on asetuksia paikallista kehitystä varten, kuten tietoja tallennuksesta ja hosting-mallista. Jos AzureWebJobsStorage-asetus puuttuu, lisää se ja aseta "UseDevelopmentStorage=true".

Yksinkertaisen funktion toteuttaminen

Seuraavaksi toteutamme funktion, joka muuntaa numerot sanoiksi. Tämä on yksinkertainen esimerkki, mutta havainnollistaa hyvin Azure Functions -toimintaa.

  1. Lisää uusi luokka "NumbersToWords.cs" ja kopioi sen sisältö verkkosivulta, joka tarjoaa valmiin koodin.

  2. Vaihtoehtoisesti, jos käytät Visual Studio 2022:ta, voit nimetä alkuperäisen "Function1.cs"-tiedoston uudelleen nimellä "NumbersToWordsFunction.cs" ja lisätä siihen tarvittavan koodin.

  3. Muokkaa koodia seuraavasti:

csharp
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using System.Numerics; using Packt.Shared; using System.Threading.Tasks; namespace Northwind.AzureFunctions.Service { public static class NumbersToWordsFunction { [FunctionName(nameof(NumbersToWordsFunction))]
public static async Task Run(
[HttpTrigger(AuthorizationLevel.Anonymous,
"get", "post", Route = null)] HttpRequest req, ILogger log) { log.LogInformation("C# HTTP trigger function processed a request."); string amount = req.Query["amount"]; if (BigInteger.TryParse(amount, out BigInteger number)) { return await Task.FromResult(new OkObjectResult(number.ToWords())); } else {
return new BadRequestObjectResult($"Failed to parse: {amount}");
} } } }

Tämä funktio vastaanottaa HTTP-pyynnön, jossa annetaan numero, ja palauttaa sen sanaksi muunnettuna. Jos syötettyä arvoa ei voida muuntaa numeroksi, funktio palauttaa virheilmoituksen.

Funktion testaaminen paikallisesti

Kun funktio on valmis, voit testata sen paikallisesti seuraavilla vaiheilla:

  1. Käynnistä projekti. Visual Studio Codessa varmista, että "Attach to .NET Functions" on valittuna ja paina "Run"-painiketta.

  2. Jos Windowsin palomuurista ilmestyy varoitus, valitse "Allow access".

  3. Azure Functions Core Tools suorittaa funktion oletuksena portissa 7071. Voit nyt avata selaimen ja testata funktiota paikallisesti:

bash
http://localhost:7071/api/NumbersToWordsFunction?amount=12345

Tällä tavoin voit testata, että funktio palauttaa oikean tuloksen, esimerkiksi:

nginx
Twelve Thousand Three Hundred Forty-Five

Mitä tulee huomioida

Kun työskentelet Azure Functions -projektin kanssa, on tärkeää ymmärtää, että vaikka projektit voivat olla pieniä ja itsenäisiä, ne voivat silti olla osa laajempaa pilvipohjaista arkkitehtuuria. Toisin kuin perinteisissä sovelluksissa, Azure Functionsissa maksat vain käytetystä ajasta ja resursseista, ei jatkuvasta palvelimien pyörittämisestä. Tässä piilee Azure Functionsin yksi suurista eduista.

Samalla kannattaa huomioida, että testaaminen paikallisessa kehitysympäristössä ei aina vastaa täysin pilvessä toimivaa versiota. Azure tarjoaa myös mahdollisuuden käyttää laajempaa lokitusta ja valvontaa, kuten Application Insightsia, mikä auttaa ongelmien diagnosoinnissa ja toiminnan optimoinnissa.

Miten EF Core määrittelee mallin ja käyttää konventioita, attribuutteja ja Fluent API:a?

Kun työskentelet EF Core:n kanssa, mallin määrittäminen ja sen yhteensovittaminen tietokannan kanssa on yksi keskeisistä tehtävistä. Usein tämä tapahtuu käyttäen konventioita, jotka määrittävät, miten .NET-luokat vastaavat tietokannan tauluja ja sarakkeita. EF Core tarjoaa mahdollisuuden luoda tehokkaita ja joustavia tietokantamalleja, jotka eivät ainoastaan yksinkertaista koodia, mutta myös parantavat suorituskykyä ja ylläpidettävyyttä.

Tietokannan määrittäminen alkaa usein niin sanotuilla "konventioilla", jotka oletuksena liittävät .NET-luokkien ominaisuudet ja tietokannan sarakkeet. Esimerkiksi, jos entiteetin ominaisuus on kokonaisluku tai GUID, EF Core olettaa sen olevan IDENTITY-sarake, eli sarake, jonka arvo määritellään automaattisesti tietueen lisäyksen yhteydessä. Tämä säästää aikaa ja koodin kirjoittamisen tarvetta.

On kuitenkin tärkeää muistaa, että konventiot eivät aina riitä, ja useissa tapauksissa on tarpeen lisätä tarkempia määrittelyjä. Tähän tarkoitukseen käytetään usein attribuutteja. Attribuutit, kuten [Required], [StringLength(50)] tai [Column(TypeName = "money")], antavat tarkempia sääntöjä entiteetin ominaisuuksille. Esimerkiksi, jos haluamme varmistaa, että tuotteen nimi ei ole tyhjä ja sen pituus on enintään 40 merkkiä, voimme määrittää nämä attribuutit näin:

csharp
[Required]
[StringLength(40)] public string ProductName { get; set; }

Kun nämä attribuutit on lisätty, EF Core ymmärtää, että ProductName-kenttä ei saa olla tyhjä ja sen pituus ei saa ylittää 40 merkkiä. Jos tietokannan luomisessa on tarve määrittää myös sarakkeen tyyppi, kuten rahasumma, joka ei ole suoraan yhteensopiva .NET-tyypin kanssa, käytämme [Column]-attribuuttia, kuten seuraavassa esimerkissä:

csharp
[Column(TypeName = "money")]
public decimal? UnitPrice { get; set; }

Jos tietokannan taulussa sarake on määritelty tyypiksi "money", mutta .NET ei tarjoa suoraan vastaavaa tyyppiä, käytämme decimal?, joka vastaa parhaiten "money"-tyyppiä.

Lisäksi voidaan käyttää Fluent API:a, joka on toinen tapa määritellä malli. Fluent API mahdollistaa entiteettien määrittämisen suoraan koodissa ilman attribuuttien käyttöä, mikä voi pitää luokat siisteinä ja helposti ylläpidettävinä. Esimerkiksi sama kenttä voidaan määritellä seuraavasti ilman attribuutteja:

csharp
modelBuilder.Entity<Product>()
.Property(product => product.ProductName) .IsRequired() .HasMaxLength(40);

Fluent API voi myös auttaa tietokannan alustamisessa. Esimerkiksi voimme määrittää, että tietokannan täytyy sisältää ainakin yksi tuote, jolloin voimme lisätä tietueen suoraan:

csharp
modelBuilder.Entity<Product>() .HasData(new Product { ProductId = 1, ProductName = "Chai", UnitPrice = 8.99M });

Tämä varmistaa, että tietokannassa on aina ainakin yksi tuote, joka helpottaa testauksen ja datan hallinnan aloittamista.

Tärkeä huomio on se, että EF Core:n avulla voi käsitellä myös olemassa olevia tietokantoja, ja sen ei aina tarvitse luoda tauluja alusta alkaen. Jos käytetään olemassa olevaa tietokantaa, voidaan hyödyntää niin sanottua "reverse engineering"-tekniikkaa, jossa EF Core luo mallit olemassa olevista tauluista. Tämä voidaan tehdä esimerkiksi komentoriviltä seuraavalla komennolla:

bash
dotnet ef dbcontext scaffold "Data Source=.;Initial Catalog=Northwind;Integrated Security=true;TrustServerCertificate=true;"

Tämä komento luo kaikki tarvittavat mallit ja yhteydet olemassa olevaan tietokantaan, jolloin voidaan jatkaa kehitystyötä ilman tietokannan luomisen vaihetta.

Kun mietitään entiteettien mallintamista ja tietokannan kanssa työskentelyä EF Core:lla, on tärkeää muistaa, että konventioiden lisäksi attribuutit ja Fluent API tarjoavat laajat mahdollisuudet hienosäätää tietomallia. Tämän kautta voidaan varmistaa, että tietokannan rakenne on tarkasti määritelty ja sen hallinta on helppoa pitkällä aikavälillä.

Tietokannan suunnittelu ei ole pelkästään koodin kirjoittamista, vaan myös tärkeä osa sovelluksen suorituskykyä ja ylläpidettävyyttä. Tämän vuoksi on olennaista ymmärtää, miten erilaiset attribuutit ja konventiot vaikuttavat tietokannan rakenteeseen ja miten nämä voivat parantaa ohjelmiston laatua.