# Azure Functions ## Nodige tools - Visual Studio Code - Azure Portal - Azure Data Studio ## Doelstellingen - Aanmaken Azure Functions Project met Visual Studio Code - Hosten van Azure Functions in de Cloud - Aanmaken SQL Database op Azure - Maken van Webservices in Azure Functions op bestaande SQL Server Database ## Opdracht We gaan een SQL Database opzetten met webservice die we verder nodig zullen hebben voor Create 3. U zal dus de SQL Database actief moeten laten en NIET wissen op het einde van deze les. Hetzelfde verhaal voor de Azure Function App. Deze moet ook blijven staan. We zullen telkens zo goedkoop mogelijk werken. <span style="color:red">**Opgepast: we werken in week 4 verder aan deze oefening. Zorg dat je deze nog hebt tegen dan.**</span> ## Dotnet & Azure Functions Tools Voor we kunnen starten met programmeren moeten volgende .NET SDK's op je systeem staan: - .NET Version 6.0 of hoger - Azure Functions Core Tools V4 Controleer via de command prompt of .NET 6.0 of hoger op je systeem staat door het volgende commando te tikken ``` dotnet --version ``` Onderstaande versie 6.0 of hoger moet verschijnen. ![](https://i.imgur.com/1oYzRiQ.png) Indien je .NET 6.0 niet staan hebt moet je dit installeren. Ofwel via https://dotnet.microsoft.com/en-us/download/dotnet/6.0 ofwel door Visual Studio 2022 te installeren (ook nodig voor ander vak). Naast .NET 6.0 moeten we ook de Azure Functions Core Tools installeren. Tik onderstaande in om te controleren of je deze reeds staan hebt. ``` func init ``` Ondertaande melding moet verschijnen: ![](https://i.imgur.com/kiSxVQm.png) Indien bovenstaande melding niet verschijnt moet je deze nog installeren. Je kan deze downloaden via https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=v4%2Cwindows%2Ccsharp%2Cportal%2Cbash.**Na de installatie best je command prompt herstarten**. ## Visual Studio Code Installeer volgende extensions in Visual Studio Code: **Azure Tools Extensions**: deze zal in één beweging onderstaande extensions toevoegen voor het beheren en werken met Azure. * ms-azure-devops.azure-pipelines * ms-azuretools.vscode-azureappservice * ms-azuretools.vscode-azurefunctions * ms-azuretools.vscode-azureresourcegroups * ms-azuretools.vscode-azurestaticwebapps * ms-azuretools.vscode-azurestorage * ms-azuretools.vscode-azurevirtualmachines * ms-azuretools.vscode-bicep * ms-azuretools.vscode-cosmosdb * ms-azuretools.vscode-docker * ms-dotnettools.csharp * ms-dotnettools.vscode-dotnet-runtime * ms-vscode.azure-account * ms-vscode.azurecli * ms-vscode.vscode-node-azure-pack * msazurermtools.azurerm-vscode-tools Daarnaast ook zeker **Azurite.azurite** extension installeren. Enkele niet Azure Extensions die wel handig zijn kan je ook best installeren: * aliasadidev.nugetpackagemanagergui * bencoleman.armview * esbenp.prettier-vscode * eservice-online.vs-sharper * vscode-icons-team.vscode-icons * ZainChen.json Toevoegen gaat via onderstaande icoon (de 4 blokjes) ![](https://i.imgur.com/JA0Wi74.png) ## GitHub Repository Maak eerst een **lege** repository aan op GitHub en clone deze lokaal op je systeem. In deze map maken we straks ons Azure Functions Project aan. ## Azure Functions Application ### Aanmaken project We maken gebruik van Visual Studio Code voor het aanmaken van het Azure Functions Project. **Navigeer naar de map op je systeem waar de GitHub repository staat**. In deze map tikken we het volgende commando zodat VS Code start: ``` code . ``` Visual Studio code zal starten en de interface zal er ongeveer als volgt uitzien (naargelang de extensions die op je systeem staan): ![](https://i.imgur.com/YJUeolg.png) We zien reeds de **.gitignore** file staan (u zou moeten weten wat dit is). Open nu in Visual Studio code een terminal venster of ga naar de commandprompt en navigeer naar de map waar we in werken. Tik nu volgende commando om een nieuw Azure Functions project te maken: ``` func init ``` ![](https://i.imgur.com/4NgUwkP.png) In het bovenstaande menu moeten we kiezen op welk platform we de Azure Funtions willen programmeren. Wij kiezen voor (1) dotnet. ![](https://i.imgur.com/g7QsKuj.png) Nu moeten we de programmeertaal kiezen, we kiezen (1) C#. Daarna zal het project aangemaakt worden. ### Project structuur Een leeg project bevat toch reeds een aantal belangrijk files. We bespreken deze even kort. De file met de extensie **.csproj** is een beschrijving van ons project en zal gebruikt worden door Visual Studio om de juiste packages(nuget) te downloaden die nodig zijn. Daarnaast bepalen we ook daar de versie van .NET en Azure Functions die we willen gebruiken. Manueel moeten we hier soms nieuwe packages toevoegen. ![](https://i.imgur.com/UuZjW5C.png) Een tweede belangrijke file **local.settings.json**. Deze file gebruiken we om instellingen in te plaatsen die we soms nodig hebben in onze Azure Functions applicatie. Dit kan gaan om database settings of mailserver settings. Dit is niet de beste oplossing maar om lokaal te testen is dit ideaal. Later zie we veiliger oplossing. **Het is ook zeer belangrijk dat deze file NOOIT op GitHub komt**. De laatste file is **host.json**. In deze file moeten we soms config info vermelden voor de runtime. We hebben deze minder nodig ### Triggers Azure Functions maakt gebruik van het concept van **Triggers**. Dit zijn stukjes code die geactiveerd kunnen worden op verschillende manieren. Dit kan heel eenvoudige via een HTTP Request maar kan ook door het ontvangen van berichten die dan verwerkt moeten worden. In deze module gaan we veel gebruik maken van triggers. We starten met de meest eenvoudige, de **HTTP Trigger**. Via **View -> Command Palette** kunnen we in Visual Studio Code taken uitvoeren. Wij kiezen voor **Azure Functions: Create Funtion**. (tip: probeer de shortcuts te gebruiken om dit te activeren via keyboard). ![](https://i.imgur.com/Fd4suNF.png) Nu moeten we het soort **Trigger** kiezen. Wij gaan voor **HTTP Trigger** en dit **zonder** OpenAPI. Dit is een trigger die we via een eenvoudige HTTP GET of POST kunnen activeren. ![](https://i.imgur.com/2sxAkDY.png) We vullen een geldige naam in: ![](https://i.imgur.com/5QlmkIe.png) Daarna vullen we de .NET Namespaces in: ![](https://i.imgur.com/MlfwsXy.png) Als laatste kieze we bij accessrights **Anonymous**, iedereen kan de trigger aanspreken? ![](https://i.imgur.com/a4vYpXe.png) Azurite is een extensions die een aantal basis Azure Services gaat simuleren. Dit gaat van table storage tot blob storage. We zien later wat dit precies is. We moeten deze extensie activeren voor we Azure Functions kunnen aanmaken en testen. ![](https://i.imgur.com/8LEV2av.png) Start nu de Azure Functions app via **Run -> Start Debugging**. In de terminal van Visual Studio Code zal er meer info verschijnen zoals de URL van de HTTP Trigger vb: http://localhost:7071/api/HelloWorld. ![](https://i.imgur.com/thGXB5g.png) Test de URL nu uit via de browser (HTTP GET) of via Postman (GET OF POST). ## HTTP Trigger GET Voeg een nieuwe HTTP Trigger toe, ik noem deze **CalculatorTrigger**. We gebruiken **anynmous** voor security. Een nieuwe trigger zal tevens in een nieuwe bestand komen, dit is niet verplicht maar wel handig. We gaan nu wat meer in detail de HTTP Trigger bestuderen. ![](https://i.imgur.com/6o2puTX.png) We beginnen met het attribuut **[FunctionName("...")]**. Dit attribuut beschrijft de naam van de Azure Function en zal gebruikt worden voor weegave in de portal. Dit moet uniek zijn en u mag deze zelf kiezen. Daarna begint de C# functie code. De methode is** public static async**. Dit wil zeggen dat de methode asynchroon zal werken en publiek is. U zal dit ook zien in de module device programming, maar dan in de diepte. De naam van de methode is **Run**. U mag dit wijzigen naar iets anders indien u dit wenst. Belangrijkers voor ons zijn de parameters. De eerste parameter is **[HttpTrigger(AuthorizationLevel.Anonymous)]**. Hiermee zeggen we dat we een HTTP Trigger wensen die anoniem toegankelijk is. Je kan dit wijzigen als je wil. De HTTP Verbs **GET** en **POST** duiden aan dat we zowel een HTTP GET als POST kunnen gebruiken om de HTTP Trigger te activeren. Het is best hier **één** verb te kiezen. Wijzig dit zodat we enkel GET gebruiken. Je mag dus POST wegdoen. De route is de URL die we kunnen opgeven om de functie/trigger aan te roepen. Je mag dit terug vrij kiezen. Als laatste hebben we **HttpRequest** req en **ILogger** log. De eerste is een object data alle info over het low level HTTP request bevat. De laatste is een object die we kunnen gebruiken om informatie te loggen of te debuggen. In de methode printen we via **log.LogInformation** basis info af. Het object **OkObjectResult** zal een HTTP object met statuscode 200 terugkeren zonder data (we geven lege string door). Wijzig nu de code als volgt, en test uit in postman, controleer zeker goed de route die we hebben opgegeven. ![](https://i.imgur.com/5YfdhZd.png) Test dit nu via postman: ![](https://i.imgur.com/jm5vzzM.png) We hebben gekozen voor een HTTP GET. Dit wil zeggen dat we de info via de URL moeten meegeven. Dit kunnen we doen via parameters in de route. Wijzig de route als volgt zodat we getal1 en getal2 als parameter meegeven. ![](https://i.imgur.com/IpAkPTX.png) Daarna moeten we ook de C# functie aanpassen zodat we iets kunnen doen met de parameters in onze functie. We voegen **int getal1** en **int getal2** toe bij de methode signatuur. De namen zijn zeer belangrijk en moeten hetzelfde zijn als deze in de route. ![](https://i.imgur.com/9Ze8rS6.png) Als laatste keren we de som terug van beide via **OkObjectResult**. ![](https://i.imgur.com/AfjmEo1.png) Test nu terug uit via Postman: ![](https://i.imgur.com/XGUth2r.png) ### Opdracht Wijzig de functie en zorgt dat we ook de operator kunnen meegeven via de route (+,-,* of /). Je mag maar één HTTP Trigger gebruiken. Test dit uit in Postman. ### Json Meestal willen we JSON terugkeren vanuit onze trigger. Nu keren we gewoon een tekst terug. We gaan dit aanpassen. Maak een folder aan in het project en voeg een klasse **CalculationResult.cs** toe. Deze klasse zal het resultaat van onze HTTP Trigger beschrijven. De klasse ziet er als volgt uit: ![](https://i.imgur.com/l13L36p.png) Wijzig nu de vorige opracht zodat we een object van dit datatype terugkrijgen Dit ziet er als volgt uit in Postman. ![](https://i.imgur.com/Ljqz4Ci.png) ## HTTP Trigger POST In het vorige stuk hebben we via de route in de URL data meegegeven. Dit is makkelijk wanneer we weinig data moeten doorgeven voor de URL. Wanneer het om meer data gaat dan moeten we een HTTP POST gebruiken. dit wil zeggen dat we niet via de URL maar via de body van het HTTP request de data zullen versturen. Vergeet niet de methode aan te passen en GET door POST te vervangen. Eerst gaan we beschrijven hoe de data van de request er moet uitzien. Voeg een nieuwe klasse toe in de map **Models** en noem deze **CalculationRequest.cs**. Deze klasse bevat de properties Getal1, Getal2 en Operator. Kies zelf de juiste datatypes. Wannee we deze straks posten in Azure Functions dan moeten we de dat uit het HTTP Request inlezen en omzetten naar een object van het type **CalculationRequest**. Dit doen we als volgt: ![](https://i.imgur.com/xJUvTCB.png) Pas nu zelf verder aan tot alles werkt en test de POST uit via Postman. Kijk goed naar onderstaande screenshot: ![](https://i.imgur.com/XEORriX.png) ## Azure Functions Deployment Tot nu toe testen we alles lokaal op onze machine. Uiteindelijk is het de bedoeling dat we alles in de Cloud op Azure gaan draaien. Hiervoor maken we eerst een nieuwe **Azure Function App** aan in de portal. Maak een nieuwe resource group aan voeg een Function App toe. Mijn instellingen kan u hieronder zien: ![](https://i.imgur.com/yEGegEj.png) Belangrijk zijn volgende instellingen: - kies voor Code en niet Docker Container - Runtime stack is .NET - Versie is 6 van .NET - Als Operating System kiezen we Linux Maar de meeste belangrijke instelling is **Plan Type**. Hier kiezen we voor **Consumption (Serverless)**. Dit wil zeggen dat we betalen per request. Alleen zijn de eerste 1 miljoen request gratis. Dit is ideaal voor ons om te starten. Daarna laat je Azure de resource aanmaken. Als dit afgelopen is ziet dit er ongeveer als volgt uit: ![](https://i.imgur.com/ovQLTZe.png) Klikken we op deze service dan komen we in het overzicht van de Function App. We zien grafieken, de URL van de function app etc... Onze applicatie staat echter nog niet online. Kies in het menu link voor **Deployment Center**. Via dit scherm koppelen we nu de GitHub repo aan de Azure Function app. Probeer dit zelf en test dan de online versie uit via Postman. Als we nu veranderingen doen in onze code op onze PC en we pushen deze code naar GitHub dan zal er automatisch een nieuwe versie online komen. Dit is onze eerste **Dev Ops** pipeline. Later in 2MCT gaan we hier dieper op in. Probeer misschien zelf te ontdekken hoe dit werkt. Tip: kijk in de GitHub repository, er is daar plots een nieuwe map aangemaakt. ## Azure SQL Database In deze opgave gaan we vanuit Azure Functions een Azure SQL Database aanspreken. We maken eerst een **Azure SQL Database** aan in de Cloud. Ga je naar resource group en voeg [](https://i.imgur.com/dgUTaOq.png) Maak een nieuwe resource group voor deze oefening, de naam kiest u zelf. Voeg in deze resource group een SQL Database toe. ![](https://i.imgur.com/3LRB2zf.png) Vul daarna de verschillende opties in: ![](https://i.imgur.com/rBNxcee.png) Configureer zoals hieronder, enkel server naam moet uniek zijn. **Vergeet zeker niet de Compute + Storage te wijzigen naar Basic.** ![](https://i.imgur.com/MJiZzMS.png) Daarna zal deze aangemaakt worden. Wanneer dit klaar is zien we twee nieuwe services, een Database Server en een database. Op één server kunnen we meerdere databases aanmaken. ![](https://i.imgur.com/8RCPCt3.png) We kunnen nu op verschillende manieren connecteren met deze database. Volgens tools zijn beschikbaar: - SQL Server Management Studio (Windows Only) - Azure Data Studio (Windows/Mac/Linux) - Query Editor in browser in de portal? Wij gaan de tweede manier proberen. De andere kan u zelf testen indien u dit wenst. Voor we kunnen connecteren moeten we eerst onze Office 365 Account als Admin toegang geven in de databse server. Open het scherm **Azure Active Directory** om de connectie te maken. ![](https://i.imgur.com/V5FKfpL.png) Kies nu **Set Admin** en rechts vul je uw Howest e-mailadres in zodat uw account de Admin voor de database is. Vergeet niet op **save** te duwen bovenaan. Je kan nu Azure Data Studio downloaden via https://docs.microsoft.com/en-us/sql/azure-data-studio/download-azure-data-studio?view=sql-server-ver16. Installeer ook best volgende **extensions**: - Admin Pack for SQL Server - Azure SQL Migration - Database Administration Tool Extensions for Windows - SQL Server Import Na de installatie kan je dit openen en kies e voor **Create a connection**. Het enige wat we moeten invullen is de URL van de database server en we moeten **Azure Active Directory - Universal with MFA support** kiezen. Azure Data Studio zal nu gebruik maken van onze Office 365 account om in te loggen (deze waarmee we ook op onze PC zijn actief zijn). Je zou de foutmelding moeten krijgen dat het IP niet toegelaten is. Default zal SQL Database alle IP's blocken die willen connecteren. Je kan dit whitelisten via onderstaande scherm in de SQL Server in de portal: ![](https://i.imgur.com/5YFl2FL.png) Als dit gelukt is kan je nu normaal vlot connecteren: ![](https://i.imgur.com/oeqCIjO.png) Probeer nu zelfstandig te zoeken hoe je de file **Bezoekers.csv** op LEHO kan importeren in de database. ## Oefening Bezoekers In deze oefening gaan we onze Azure Function App uitbreinden met een HTTP Trigger voor het ophalen van de bezoekers uit de database die we hierboven hebben aangemaakt. ### Ophalen Dagen Functie De eerste functie die we zullen toevoegen is deze die alle dagen zal ophalen. Voeg een nieuwe HTTP Trigger toe met als naam **GetDagen**. Wijzig de bestaande functie zodat deze er als volgt uitziet: We noemen ze **GetDagen** , de HTTP Verb is **GET** en de route is “**days**” ![](https://i.imgur.com/kaZLf06.png) In deze functie moeten we nu praten met de SQL Server om data op te halen. Hiervoor moeten de we **System.Data.SqlClient** library gebruiken. We kunnen deze toevoegen via het Command Palette en dan kiezen we **NuGet Package Manager: Add Package**. Je zal deze optie enkel hebben als je de extension geïnstalleerd hebt van in het begin. ![](https://i.imgur.com/huU36TF.png) Daarna vullen we de naam van de package in: **System.Data.SqlClient**. Nuget zal deze zoeken online en dan voorstellen welke versie we moeten nemen. We nemen de laatste. Na het toevoegen zal ook onze **.csproj** file aangepast worden: ![](https://i.imgur.com/8jqullG.png) Je zou dus ook gewoon deze file kunnen aanpassen. Open nu een nieuwe terminal in VS Code en tik **dotnet restore**. Dit zal er voor zorgen dat de package gedownload zal worden. Om te praten met SQL Database in C# hebben we een tal objecten: - **SqlConnection**: maken van connectie naar server - **SqlCommand**: opstellen van SQL statement voor de server - **SqlDataReader**: uitvoeren van SQL statement en data ophalen Voor we beginnen maken we eerst een variabele days die alle de op te halen dagen zal bevatten: ![](https://i.imgur.com/lDOkwt7.png) We beginnen met het maken van een connectie via **SqlConnection**. We maken hiervoor gebruik van het C# **using** statement. Via dit statement moeten we ons geen zorgen maken dat bepaalde verbindingen na gebruik blijven openstaan waardoor ze resource verbruiken. In de **constructor** geven we de connnectonstring mee zodat **SqlConnection** weet naar waar hij moet connecteren. We halen deze uit de settings file via **Environment.GetEnvironmentVariable()**. Daarna openen we via de methode **OpenAsync().** ![](https://i.imgur.com/VH5utH1.png) Als de connectie Open is kunnen we het SQL-commando opstellen via **SqlCommand**. We maken eerst een nieuw **SqlCommand** object aan en geven het **connection** obect door aan het **SqlCommand** zodat deze weet via welke **connectie** hij moet werken. ![](https://i.imgur.com/XFvyMUa.png) Daarna kunnen we het SQL-statement opstellen en doorgeven aan het **SqlCommand** object via de property **CommandText.** Merk op: we gebruiken een **DISTINCT**. Weet u waarom ? ![](https://i.imgur.com/pMDjfpm.png) Alles is nu klaar om de data op te halen uit de database. Hiervoor maken we gebruik van een **SqlDataReader**. We maken een nieuwe **SqlDataReader** aan door de methode **ExecuteReader** aan te roepen van het **SqlCommand** object. Daarna gaan we via een **while** **lus** de **Read**() methode van de **reader** ondervragen. Per iteratie krijgen we een **rij** binnen. Van deze rij vragen we de waar van kolom “**DagVanDeWeek**” op. We zetten deze om naar een **String** via **ToString**() en slaan op in de lijst **days**. ![](https://i.imgur.com/g12X1Gc.png) De laatste stap is de lijst terugsturen met de juiste statuscode. ![](https://i.imgur.com/8EMGP2B.png) De volledige code ziet er als volgt uit. ![](https://i.imgur.com/VOdS74C.png) Als we dit gaan testen zal dit niet werken. We moeten immers nog de connectionstring toevoegen in de **local.settings.json**. De connectionstring kunnen we vinden in Azure bij onze database: ![](https://i.imgur.com/Ce8DREn.png) We kopïeren deze voor ADO.NET en plaatsen deze in onze **local.settings.json** file. Je moet ook nog het paswoord invullen in de connectionstring. ![](https://i.imgur.com/2GozCEO.png) Test dit nu lokaal uit met Postman en u zou dit moeten krijgen: ![](https://i.imgur.com/sBmsBww.png) ## Exceptions & statuscodes Indien we volledige correct wensen te zijn dan moeten we ook de fouten opvangen die kunnen ontstaan en de juiste foutcode terugsturen. We zullen onze code moeten aanpassen en een try/catch voorzien. In het try block voeren we de code uit die de data zal ophalen. Het catch block zal de eventuele exception opvangen, loggen en de juiste foutcode terugsturen. Dit ziet er als volgt uit: ![](https://i.imgur.com/V9pKR82.png) ## Functie Ophalen bezoeken per dag De laatste functie die we nodig hebben is het ophalen van de bezoeken op een dag. Hiervoor moeten we de gekozen dag doorgeven via de URL. Vb: …/api/visitors/woensdag. Het resultaat is een lijst van JSON-objecten die er als volgt uitzien: ![](https://i.imgur.com/eIfyVF7.png) We zullen dus een klasse moeten maken die we gaan gebruiken om de JSON te genereren. Voeg een klasse **Visit** toe die er als volgt uitziet: ![](https://i.imgur.com/ez3ELjI.png) Probeer nu zel de rest van deze functie te schrijven, test lokaal en plaats finaal ook online. ## Conclusie In dit labo hebben we heel wat zaken gezien. We hebben ons eerste Azure Function aangemaakt die direct gaat praten met een Azure SQL Database. Daarnaast hebben we ook alles online gezet via een eerst DevOps pipeline. **Probeer dit labo volledig opnieuw te maken zodat je vlot leert werken met zowel de Azure Portal, Azure Data Studio als Visual Studio Code.**