Webblog

gRPC, wat is het en wanneer gebruik je het?

gRPC, wat is het en wanneer gebruik je het?

Als je op de hoogte bent van de ontwikkelingen van .NET (Core), dan weet je waarschijnlijk dat Microsoft geen WCF-projecten meer ondersteunt. Tegelijkertijd zijn gRPC projecten toegevoegd aan het portfolio van serviceoplossingen. Maar wat is gRPC, hoe verhoudt deze technologie zich tot OpenAPI of GraphQL en wanneer zou je gRPC inzetten? Op deze vragen wil ik in deze blogpost ingaan.

API driven development in een breder perspectief

Voordat ik de details in duik van de verschillende serviceprotocollen, wil ik stilstaan bij het waarom van deze ontwikkeling. Toen ik twintig jaar geleden begon met softwareontwikkeling, was het redelijk standaard dat applicaties als monoliet werden gebouwd. Dit model was eenvoudig en bestond vaak uit een client applicatie met een database. Naarmate applicaties groter en complexer werden, ontstond de wens om de monoliet op te splitsen in kleinere blokken. Een oplossingsrichting om hiermee om te gaan, was de Service Oriented Architecture. Binnen de Microsoft stack betekende dat meestal applicaties die opgebouwd waren uit WCF-services. Daarnaast kon je met deze services relatief eenvoudig externe partners aansluiten op je applicatie landschap. Nadeel is dat het gebruikte SOAP protocol log en relatief traag is. Met de opkomst van webapplicaties en apps werd in rap tempo overgestapt op WebAPI’s. De meeste van deze API’s voldoen aan de OpenAPI standaarden en implementeren in meer of mindere mate de principes van een RESTful api.

Risico van de populariteit van WebAPI’s is in lijn met de uitspraak: als je alleen een hamer hebt, ziet elk probleem er als een spijker uit.

De laatste jaren zijn er naast de bekende OpenAPI standaarden nieuwe standaarden uitgekomen die elk hun eigen probleemgebied oplossen. Door de juiste techniek in te zetten op de juiste plek, maak je een betere softwareoplossing.

OpenAPI versus graphQL versus gRPC

Naast de populaire OpenAPI standaard, zijn momenteel graphQL en gRPC opkomende alternatieven. GraphQL is vooral krachtig wanneer je de client meer specifiek data wilt laten opvragen. Het is een mooie techniek waarmee aan de hand van een schemadefinitie de client specifiek gegevens op kan vragen bij een enkel query endpoint. GraphQL ondersteunt ook mutaties waardoor je snel een rijke client kunt bouwen. De gRPC standaard is ontwikkeld om snelle en directe communicatie tussen (micro)services op te zetten. Het binaire formaat maakt de communicatie effectief en de protobuffer contracten maken het een platformonafhankelijke oplossing.

Wat is gRPC

RPC of Remote Procedure Calls zijn een van de oudste manieren om API-communicatie op te zetten. De Google implementatie ervan is een nieuwe techniek om op uniforme manier machine to machine communicatie mogelijk te maken. De basis van een gRPC service is de servicedefinitie die in een protocol buffer file is opgesteld:

blank

De definitie in deze proto file bepaalt hoe zowel de client als de server opgebouwd worden en vormt het contract tussen beide partijen. De gebruikte taal is goed gedocumenteerd door Google.

Op basis van de proto file zal Visual Studio alle benodigde code genereren om een server of client te maken. De implementatie van de code bepaal je zelf, door de gegenereerde base classes te implementeren:

blank

Ook de client wordt automatisch gegenereerd op basis van de proto file:

blank

Voorwaarden om gRPC te gebruiken

Een gRPC service draait alleen over http/2 met TLS. Wanneer je de native Kestrel server gebruikt binnen .NET, heb je standaard support voor http/2. Binnen IIS moet je extra werk doen om gRPC te kunnen hosten: zie hiervoor de Microsoft documentatie.

Belangrijkste voordelen van gRPC

  • Bijzonder lage latency
  • Optimaal om in een distributed systeem (micro)services met elkaar te laten communiceren
  • Breed ingezet door onder andere Netflix, Cloudfare, Google en Docker
  • Ondersteunt bi-directionele streaming

Wanneer gebruik je gRPC

Vrijwel alle implementaties van gRPC zijn bedoeld voor interne snelle communicatie in een distributed systeem. Een gRPC implementatie maakt het mogelijk dat twee services met elkaar communiceren met dezelfde eenvoud als wanneer ze een interne methode aan zouden roepen. Wanneer je gRPC services publiek toegankelijk wilt maken, zul je na moeten denken over de beveiliging. Een gRPC service ondersteunt token based security, maar je zult in dit geval zowel op de client als op de server extra code moeten schrijven. Een gRPC service is niet geschikt voor communicatie met web clients. Er zijn wel initiatieven op dit gebied met gRPC web, maar dat lijkt op zoeken van een oplossing voor een niet‑bestaand probleem omdat juist voor weboplossingen OpenAPI standaarden heel goed werken.

Kennismaken met gRPC

Er is goede documentatie beschikbaar over het implementeren van gRPC in .NET. De documentatie van Microsoft is een prima startpunt om je eerste eigen service op te zetten:

https://docs.microsoft.com/en-us/aspnet/core/tutorials/grpc/grpc-start?view=aspnetcore-5.0&tabs=visual-studio

Daarnaast is de documentatie voor het maken van de proto file goed beschreven:

https://developers.google.com/protocol-buffers/docs/overview

© Auteur: Menno Jongerius © 2021 Bergler Competence Center

Volg ook ons webinar over gRPC op 5 oktober aanstaande! Meer informatie en gratis aanmelden >>>

berglergRPC, wat is het en wanneer gebruik je het?
Lees meer

GitHub actions vs Azure DevOps Pipelines

GitHub actions vs Azure DevOps Pipelines

Nadat Microsoft in 2018 GitHub heeft overgenomen was het even afwachten welke in richting GitHub zou bewegen. Zou het een separate merknaam blijven of zou het geassimileerd worden binnen de bestaande Microsoft portefeuille? Nu na 3 jaar is het veilig om te zeggen dat GitHub als merk blijft bestaan. Vrij logische keuze omdat Microsoft welliswaar zijn eigen tegenhanger heeft met Azure DevOps maar het marktaandeel van GitHub is vele malen groter. Zeker als we sec kijken naar de source control mogelijkheden. (77% voor github vs 6% voor DevOps volgens een onderzoek van JetBrains: https://www.jetbrains.com/lp/devecosystem-2020/team-tools/)

Beide services bieden veel meer dan alleen source control en hier zien we ook de verschillen. Eén van de dingen die een tijdje terug zijn geintroduceerd in GitHub zijn de CI/CD mogelijkheden in GitHub Actions. Van oudsher had Microsoft hier al veel features voor in Azure DevOps en zijn voorganger TFS. We zien hier dat GitHub meer naar Azure DevOps aan het toebewegen is. Dus reden om eens kijken naar de verschillen en eventuele overlap van mogelijkheden.

Build pipelines Classic vs Modern

blank
Zoals eerder aangegeven heeft Azure DevOps en zijn voorganger TFS al tijden mogelijkheden tot het opzetten van een CI/CD pipeline. Hier zijn grofweg 2 verschillende manieren. De inmiddels wat verouderde manier van de classic pipeline waar men een grafische interface de build en release pipeline in elkaar kan klikken.

blank
De grafische terugkoppeling is waardevol, maar er is er één groot nadeel. Deze pipeline leeft alleen in Azure DevOps en bestaat niet uit code welke in de Git repo zit. Hierdoor is het lastig om bepaalde veranderingen in de build/release pipeline af te stemmen met de code. Zo kun bijvoorbeeld een extra project toevoegen welke je apart wilt compileren binnen dezelfde build/release pipeline. Dit doe in een feature branch in je git repo. Hiervoor moet je de pipeline aanpassen en tegelijkertijd ook je code. Maar misschien is je code nog niet klaar en wil in de tussentijd ook andere branches kunnen bouwen. Dan ontstaat er een probleem.

blank
De oplossing voor dit soort problemen is het opzetten van een build/release pipeline in code en deze op te nemen in je git repo. Dan is de koppeling tussen je code en pipeline altijd 1 op 1. Dit is in Azure DevOps al enige tijd geleden introduceert met de zogenaamde moderne yaml pipelines. GitHub actions gebruikt al direct vanaf de start yaml als enige manier van opzetten van pipelines.  Voor dit vergelijk gaan we dan ook alleen kijken naar de yaml pipelines en laten de classic pipelines buiten beschouwing.

Overeenkomsten & Verschillen

Yaml scripts

Op het eerste gezicht lijken de yaml scripts van Azure DevOps pipelines en GitHub actions sterk op elkaar. Niet zo vreemd aangezien ze van dezelfde organisatie afkomstig zijn. Zo worden beide pipelines gestart middels triggers. Ze kunnen beide reageren op push events op verschillende branches en kunnen beide onderscheid maken op tags. Naast deze triggers kan men GitHub Actions pipelines starten op basis van GitHub events, dit zijn er legio en kan men b.v. een pipeline starten op basis een issue-comment – created of deleted event. Dit is niet mogelijk in Azure DevOps.  Beide oplossingen bestaan uit 1 of meerdere jobs, met daarin weer steps en tasks.  De notatie verschilt wel iets maar er zijn meer overeenkomsten dan verschillen. Er is ook documentatie beschikbaar om te migreren: https://docs.github.com/en/actions/learn-github-actions/migrating-from-azure-pipelines-to-github-actions

Agents

Naast de overeenkomsten in de syntax van yaml zijn de functionaliteit ook grotendeels overeenkomstig. Zo bieden beide platformen de mogelijkheid tot het runnen van script in een gehoste omgeving en met verschillende operating systemen zoals Linux, Windows  of MacOs. Daarnaast ook mogelijkheden om je eigen agents hiervoor te gebruiken. Het is wel zo dat Azure DevOps een eigen agents kan selecteren op basis van capabilities. Deze capabilities zijn name-value pairs die beschrijven wat een bepaalde agent kan. Zo staat daar b.v. het type van operating system en versie van de geïnstalleerde software in. Builds in Azure DevOps kunnen op basis van deze capabilities een keuze maken van beschikbare agents. In GitHub actions gaat dit op basis van labels die men als gebruiker zelf moet administreren. Dit is iets meer werk maar uiteindelijk kun je hetzelfde bereiken.

Security tools integratie

GitHub Actions heeft standaard features die een security scan op je code uitvoeren met een SAST oplossing (static application security testing). Dit is een native feature van GitHub actions en je hoeft hier geen extra  3th party tooling voor te gebruiken.  Dit kan ook in Azure DevOps maar dan moet men wel altijd gebruik maken van 3th party tooling. Daarnaast heeft GitHub Actions directe integratie met Dependabot zodat er geautomatiseerd pull requests worden aangemaakt indien een 3th party library een update heeft. Dit zijn belangrijke features voor je security beleid. Dit kan ook in Azure DevOps maar hier moet men wel zelf actie voor ondernemen.

Beschikbare standaard tasks

In Azure DevOps en GitHub Actions zijn veel verschillende standaard taken om de resultaten van de build te releasen naar veel verschillende omgevingen. Je kunt hier denken aan aan releases naar AWS, Azure, Google Cloud e.d. GitHub Actions hebben inmiddels bijna 9000 taken in marketplace staan, dit is aanzienlijk meer dan Azure DevOps (+/- 1200). Maar de belangrijkste en meest gebruikte taken zijn bij beide te vinden en zou in 99% van de gevallen voldoende moeten zijn.

Environments

Azure DevOps kent een tijdje begrippen als Environments, Stages & Templates. Hiermee is het mogelijk om per omgeving (Development, Test, Acceptance, Production) bepaalde approvals te zetten.  Je kunt hiermee bijvoorbeeld aangeven dat een acceptatie tester de release moet goedkeuren voor een release naar productie. Dit was iets was GitHub actions nog niet ondersteunde maar recent zit een soortgelijke functionaliteit ook in GitHub actions. (zie : https://docs.github.com/en/actions/reference/environments ) Deze functionaliteit is wel alleen beschikbaar in GitHub Enterprise.

Agile workflow management

Naast de build en release features biedt Azure DevOps meer functionaliteiten voor het begeleiden van je agile workflow. Denk hier aan mogelijkheden voor het maken van boards, backlogs, sprints e.d. Dit is functionaliteit die men niet in GitHub actions kan vinden maar waarvoor men dan afhankelijk is van andere tooling (b.v. Jira)

Conclusie

Beide zeer mooie en uitgebreide producten en er zijn meer overeenkomsten dan verschillen. Dus eigenlijk is keuze voor één van deze twee producten prima.  Mocht je keuze moeten maken dan is deze sterk afhankelijk van het ecosysteem waar je organisatie reeds gebruik van maakt. Zit je al in de Microsoft hoek of  wil je één product waar je hele ontwikkelproces in kunt beheren dan ligt de keuze voor Azure DevOps voor de hand. Ben je hier nog vrij om keuzes te maken of gebruik je b.v. Jira voor management van je agile workflow dan ligt dit minder voor de hand. De features die GitHub actions biedt voor integratie met security scan tooling is daar wel een sterk argument. Daarnaast lijkt GitHub actions meer momentum te hebben dan Azure DevOps en de nieuwe features volgen elkaar snel op. Dus in deze geen foute keuzes hooguit een keuze die beter aansluit bij de huidige werkwijze.

blank

Auteur: Patrick Bes © 2021 Bergler Competence Center

berglerGitHub actions vs Azure DevOps Pipelines
Lees meer

Hoe migreer je naar .NET 5

Hoe migreer je naar .NET 5

Met de komst van .NET5 en de aankondiging van Microsoft te gaan stoppen met .NET Framework dient zich de vraag aan hoe bestaande .NET Framework applicaties kunnen worden gemigreerd naar het nieuwe .NET5. Dit blog probeert de migratiemogelijkheden die Microsoft biedt te behandelen en de mogelijke problemen en/of valkuilen te beschrijven die daarbij kunnen optreden.

Een stukje historie (en toekomst)

Het werd al een tijd verwacht maar nu is het dan zover: er komt geen nieuwe versie meer van het .NET Framework. De laatste versie van het .NET Framework is versie 4.8. Uiteraard zullen er voorlopig nog broodnodige patches uitgebracht worden, maar voor nieuwe features moet je echt overstappen naar het nieuwe .NET(5) voorheen bekend als .NET Core.

Onderstaand plaatje toont de historie in de ontwikkeling van de diverse framework versies die door Microsoft op de markt zijn gebracht:

blank

Wanneer we inzoomen op het nieuwe .NET dan zien we dat Microsoft de volgende planning voor de releases uitgeeft:

blank

Zoals is te zien zal er ieder jaar een nieuwe versie van .NET worden uitgebracht waarbij het iedere twee jaar zal gaan om een zogenaamde LTS (Long Term Support) versie. Deze LTS versies zullen door Microsoft voor een periode van drie jaar ondersteund worden. Daarnaast zal er ieder jaar een major versie worden uitgebracht. Voor deze versies zal de ondersteuningsperiode 15 maanden zijn.

Migratiepaden

Welke mogelijke paden voor een migratie kunnen worden gevolgd? In principe wordt geadviseerd “zo klein mogelijke” stappen te nemen voor een migratie. Overigens wordt wél aangeraden om te starten met de applicatie naar de meest recente .NET Framework versie te brengen, zijnde .NET Framework 4.8.

Onderstaand plaatje geeft dan de mogelijke migratiepaden weer:

blank

Migratietools

Om je te helpen bij het migreren van applicaties van het oude .NET Framework naar het nieuwe .NET5 heb je een aantal tools tot je beschikking. Deze zijn onder te verdelen in twee categorieën:

  1. Portability analyzers

Dit zijn tools die een scan/analyse uitvoeren op je bestaande applicatie en die zijn bedoeld om inzicht te krijgen in … Een voorbeeld van zo’n analyzer is de API Portability Analyzer tool (API-port) van Microsoft. Deze tool geeft inzicht in de ondersteuning en de mate van integratie van de .NET API’s die worden gebruikt door een applicatie op verschillende .NET platformen. Denk hierbij vooral aan de 3rd party libraries die worden gebruikt.

API-port is als plug-in te installeren in Visual Studio wat het mogelijk maakt om vanuit de IDE een compatibiliteitsrapport voor de solution te genereren.

  1. Porting applicaties

Deze applicaties gaan naast de analyse ook daadwerkelijk een poging doen de applicatie te migreren naar een nieuwere versie .NET. Voorbeelden hiervan zijn het open source project try-convert (een eenvoudige CLI tool die helpt bij het migreren van .NET Framework-projecten naar .NET Core) en .NET Upgrade Assistent (waarvan try-convert een subonderdeel is)

Een diepere kijk in de tools

Zoals aangegeven onderscheiden we twee categorieën migratietools: de portability analyzers en de porting applicaties.

API-port

Naast dat API-port als CLI-tool gebruikt kan worden is deze analyzer beschikbaar als plug-in in Visual Studio. Hierdoor komt er bij selecteren van de solution een extra optie ter beschikking: “Analyze Solution Portability”

blank

Zoals gezegd zal de analyzer geen werkelijke conversie gaan proberen uit te voeren maar genereert  het een rapport met als inhoud de compatibiliteit van de diverse projecten in de solution voor diverse targets waarnaar de conversie uitgevoerd kan worden. Tevens is in detail te zien welke onderdelen van de solution niet ondersteund worden bij een eventuele migratie. Daarnaast wordt in het overzicht ook aangegeven welke 3rd party libraries niet worden herkend en/of ondersteund:

blank

API-port is met name geschikt om vooraf een beeld te krijgen tegen wat voor problemen men aan gaat lopen bij een migratie naar .NET5.

Try-convert

Net als de andere tools/analyzers wordt deze tool geïnstalleerd via .NET Core. Het is van de twee hier besproken migratietools de eenvoudige variant. Try-convert werkt via de CLI waarbij een aantal opties kunnen worden meegegeven zoals het path naar de te migreren solution/workspace en de optie om al dan niet een back-up te maken van de solution alvorens de migratie wordt uitgevoerd. In de praktijk is het echter aan te bevelen om een aparte migratie-branch te maken in de te migreren  repository zodat op eenvoudige wijze is na te gaan wat voor wijzigingen de migratietool uiteindelijk heeft doorgevoerd.

.NET Upgrade Assistent

De meest uitgebreide en door Microsoft aanbevolen migratietool is .NET Upgrade Assistent. Deze tool is nog in ontwikkeling en er worden op zeer regelmatige basis updates van uitgegeven. Ook deze tool heeft een CLI maar het grote verschil met het hiervoor genoemde try-convert is dat de gebruiker hier stapsgewijs door een aantal fases geleid wordt. Daarnaast doet de tool met name in solutions met meerdere projecten een aantal voorstellen zoals bijvoorbeeld de volgorde waarin de verschillende projecten zouden moeten worden gemigreerd (met het oog op afhankelijkheden tussen de projecten onderling). Iedere fase in het migratieproces zal worden voorzien van de nodige logging zodat de gebruiker steeds goed zicht blijft houden op mogelijke aandachtspunten en daarnaast zelf alternatieve keuzes kan maken.

De .NET Upgrade Assistent zal zo stap voor stap ieder project in de solution afwerken en zal daarbij ook de migratie/upgrade van bijvoorbeeld de NuGet packages voor zijn rekening nemen. Try-convert doet iets soortgelijks maar het voordeel wat de .NET Upgrade Assistent biedt is dat deze in zijn beslissing het target framework meeneemt. Hier schuilt echter wel een mogelijk gevaar in: omdat de .NET Upgrade Assistent zal proberen de NuGet packages te upgraden naar de meest recente versies kan het gebeuren dat je tegen nogal wat “breaking changes” aanloopt. Hier wordt door de migratietool verder geen rekening mee gehouden. De gebruiker zal dit later zelf moeten oplossen aan de hand van build errors die optreden.

Mogelijke pijnpunten/uitdagingen bij migratie

Het zal duidelijk zijn dat bij met name de meer uitgebreide solution met meerdere projecten een aantal problemen c.q. uitdagingen kunnen optreden. Het gaat dan met name om het soort project.

In het algemeen zullen er weinig problemen te verwachten zijn bij de backend libraries. Denk hierbij aan libraries zoals een datalibrary of een project wat de businesslogica bevat. Ook API’s (MVC projecten zonder Views 😉) vallen onder de projecten waarbij weinig problemen te verwachten zijn.

Iets anders wordt het als we gaan kijken naar front-end projecten zoals bijvoorbeeld een Winforms applicatie of een MVC project. Deze projecten raken de UI waar vooral met betrekking tot Razor views etc. problemen te verwachten zijn op het gebied jQuery en/of Bootstrap. Het zal daarom een afweging zijn wat met deze projecten te doen: migreren en daarna handmatig de fouten oplossen of een UI opnieuw ontwikkelen op basis van een nieuwe technologie zoals bijvoorbeeld Blazor.

Een ander mogelijk pijnpunt is de migratie van Entity Framework 6 naar EF Core. Met name de EDMX kan hier voor grote problemen zorgen. Daarnaast is het zo dat Microsoft EF6 compatible heeft gemaakt met .netstandard 2.1 waardoor er een keuze moet worden gemaakt: kiest met voor .netstandard 2.1 dan vervalt de compatibiliteit met .NET Framework 4.8. Kiest men daarentegen voor .NET Framework 4.8 dan is het niet compatible met .NET Core/.NET5. Dit is met name een lastige keuze als met kiest voor een geleidelijke overgang (waarbij men kiest voor het migreren van een aantal projecten per fase) en niet voor een “big bang” migratie.

Daarnaast is het zo dat een aantal technologieën gewoonweg niet meer beschikbaar zijn in .NET5:

  • Windows Communication Foundation (WCF)
  • Web Forms
  • Windows Workflow Foundation

Tot slot is het zo dat zich problemen kunnen voordoen met de al eerder genoemde 3rd party NuGet packages. Als stelregel kan hierbij gehanteerd worden dat wanneer een NuGet package compatible is met .netstandard dat er dan weinig problemen te verwachten zijn. Daarnaast zal het zo zijn dat met name de grotere vaak gebruikte packages al snel een .NET5 compatible versie zullen uitbrengen, vaak nog eerder dan dat Microsoft zo ver is.

Conclusie

Met de aankondiging van Microsoft te gaan stoppen met .NET Framework is het onvermijdelijk geworden na te gaan denken over een eventuele migratie naar een toekomstbestendige .NET versie zoals bijvoorbeeld .NET5. In dit blog heb ik willen aangeven wat voor mogelijkheden daar op dit moment voor op de markt zijn. Toegegeven dat het zeker nog niet de ultieme tools zijn en dat een gedegen onderzoek nodig is om uiteindelijk tot de juiste keuze te komen: migreren of greenfield ontwikkeling. Aan de andere kant: de mogelijkheden zijn er en de ontwikkelingen in migratietools volgen elkaar snel op. Aan u de keuze 😊.

Auteur: Pieter Baart © 2021 Bergler Competence Center

berglerHoe migreer je naar .NET 5
Lees meer

C# 9.0 nieuwe features – Record types (4-4)

C# 9.0 nieuwe features – Record types (4-4)

Met de komst van C# versie 9.0 zijn er heel veel waardevolle toevoegingen gedaan aan de programmeertaal en in deze Blog serie zullen we inzoomen op een aantal belangrijke nieuwe features. Al eerder behandeld in deze serie is deel 3 “Top-level statements”, we gaan nu verder met het laatste deel: “Record types”.

Om C# 9.0 te kunnen gebruiken dien je eerst de .NET 5 runtime of SDK te installeren. Ga hiervoor naar https://dotnet.microsoft.com/download. Na installatie zal C# 9.0 de standaard C# versie zijn bij elk nieuw project gebaseerd op .NET 5.

Waarom?

In deel 2 van deze serie is al gewezen op init-only setters. Op een eenvoudige manier kun je daarmee aangeven dat properties als immutable behandeld moeten worden.

Met het nieuwe keyword record krijg je als programmeur de mogelijkheid om snel en overzichtelijk een complete class immutable te maken. Je kunt dit record dan instantiëren, waarbij de data initieel wordt gezet en daarna niet meer te wijzigen is.

Dit levert je een aantal voordelen op.

Denk aan toepassing van deze record types in een multi-threaded applicatie. Omdat het object immutable is, met andere woorden niet kan worden benaderd om wijzigingen door te voeren, kan er geen race condition optreden waarbij thread 1 gegevens leest terwijl thread 2 gegevens schrijft. Je code kan worden vereenvoudigd zonder risico op deadlocks of nog erger, berekeningen met een onverwachte uitkomst.

Een ander groot voordeel van een immutable record is dat je de betrouwbaarheid van je unittesten kunt vergroten. Stel je een applicatie voor waarbij een “ouderwetse” DTO-class door diverse methodes in een keten als parameter wordt gebruikt. Wanneer de inhoud van deze class mutable is, zul je bij het schrijven van een test op één van die methodes uit moeten zoeken of er methodes bestaan die gegevens in jouw DTO kunnen wijzigen. Dit kan namelijk impact hebben op het aantal scenario’s dat je zult moeten testen.
Een immutable record maakt het onmogelijk dat gegevens worden gewijzigd, waardoor je veilig deze uitzoekklus over kunt slaan.

Hoe?

Declareren en instantiëren

C# 9.0 biedt twee mogelijkheden om een record te declareren. Het meest eenvoudig is de volgende manier, waarbij je positional arguments toepast:

blank

Deze methode is intuïtief en overzichtelijk. De C# compiler voegt boilerplate-code zoals een constructor met parameters en een deconstructor toe zodat je direct een Object van het type Car kunt aanmaken en gebruik kan maken van enkele handige uitbreidingen. Uit de intellisense blijkt dat de aangegeven property LengthInCm gebruikt maakt van init als setter en dus inderdaad immutabel is.
Er is géén parameterloze constructor aanwezig, je bent dus verplicht om de parameters via de constructor te vertrekken.

blank

Veel controle over Racecar heb je natuurlijk niet, nuttige zaken als het inbouwen van validatie of het aangeven van een default value is zo niet mogelijk. Daarom is ook de meer klassieke ogende methode beschikbaar waardoor je bijvoorbeeld berekende properties of methodes kunt toevoegen.

blank

Vergelijken van records

Een mooie eigenschap van een record is dat het zuiver gezien een reference type is, maar dat het zich gedraagt als een value type. Dit heeft een belangrijk effect op het vergelijken van instances van records.
Bij de vergelijking wordt namelijk – net als bij een echt value type – niet gekeken of de instances naar hetzelfde object verwijzen, maar of het type en de inhoud van de record instanties overeenkomen.

De bijgaande test brengt dit mooi in beeld.
Er worden 2 aparte instanties van PersonRecord aangemaakt en vervolgens vergeleken via de ==-operator en de AreEqual methode. Met classes zijn we gewend dat dit verschillende objecten zijn en daarom verwachten we dat de test faalt. Maar omdat records zich gedragen als value types slaagt deze test.

blank

Muteren van een record

Hoewel een record immutable is, is het wel mogelijk een kopie te maken van een instantie en daarbij kleine wijzigingen aan te brengen met behulp van het keyword with op de volgende manier:

blank

Verder?

Bij het record type krijg je nog een aantal andere methodes tot je beschikking.

ToString()

Deze methode levert automatisch de inhoud van het type en alle publieke properties.

blank

Deconstructor()

De deconstructor geeft je de mogelijkheid om op de volgende manier de gegevens uit je record te verzamelen.

blank

berglerC# 9.0 nieuwe features – Record types (4-4)
Lees meer

C# 9.0 nieuwe features – Top-level Statements (3-4)

C# 9.0 nieuwe features – Top-level Statements (3-4)

Met de komst van C# versie 9.0 zijn er heel veel waardevolle toevoegingen gedaan aan de programmeertaal. In deze Blog serie zullen we inzoomen op een aantal belangrijke nieuwe features. We gaan nu verder met “Top-level Statements”.

Om C# 9.0 te kunnen gebruiken dien je eerst de .NET 5 runtime of SDK te installeren. Ga hiervoor naar https://dotnet.microsoft.com/download. Na installatie zal C# 9.0 de standaard C# versie zijn bij elk nieuw project gebaseerd op .NET 5.

Waarom?

Elke .NET assembly die uitvoerbaar is, dient een entrypoint te hebben anders heeft de applicatie geen startpunt. Dit startpunt is de welbekende Main methode. Zelfs een simpele console applicatie heeft een Main methode nodig om te kunnen functioneren.

Het requirement van zo’n Main methode maakt dat C# een ietwat minder toegankelijke programmeertaal is voor beginners. Wanneer beginners de volgende code onder ogen krijgen, kan dat best intimiderend overkomen:

blank

Het enige wat bovenstaande code moet doen is de tekst “Hello World!” tonen op het scherm, maar voordat de applicatie zover is moet er dus eerst heel veel “ceremonie” plaatsvinden:

  • using
  • namespace
  • class
  • Main methode definitie (het startpunt).

De nieuwe C# 9.0 feature “Top-level Statements” maakt deze ceremonie overbodig en dus hopelijk ook wat meer toegankelijk voor beginners!

Hoe?

De volgende code is vanaf C# 9.0 uitvoerbaar geworden op zichzelf, zonder extra code:

blank

Zoals je kan zien is deze code van alle “ceremonie” ontdaan, dus geen class definitie en geen Main methode definitie meer. Je kunt je vast voorstellen dat dit veel beter te begrijpen is voor een beginner dan de eerdere voorbeeldcode.

using statements zijn gewoon nog te gebruiken om te voorkomen dat je steeds de fully qualified type namen moet specificeren:

blank

Verder?

Ondanks dat er geen Main methode is gedefinieerd, ben je nog steeds in staat om de args parameter te gebruiken om de command-line parameters uit te kunnen lezen:

blank

Wanneer de Top-level Statements het await keyword bevatten, zal de C# compiler onderwater automatisch een async entrypoint maken:

blank

De mogelijkheid bestaat nog steeds om een int waarde terug te geven, welke aangeeft wat de zogenaamde exitcode is van je applicatie.

blank

Maar?

Bij het gebruik maken van Top Level Statements zijn er wel een tweetal beperkingen waar je rekening mee moet houden.

  • Top Level Statements kunnen slechts in één bestand onder het project aanwezig zijn.
  • In principe geen nieuwe regel, maar wanneer er Top Level Statements aanwezig zijn in een project, mogen er geen andere entrypoints bestaan.
berglerC# 9.0 nieuwe features – Top-level Statements (3-4)
Lees meer

C# 9.0 nieuwe features – Pattern Matching (2-4)

C# 9.0 nieuwe features – Pattern Matching (2-4)

Met de komst van C# versie 9.0 zijn er heel veel waardevolle toevoegingen gedaan aan de programmeertaal. In deze Blog serie zullen we inzoomen op een aantal belangrijke nieuwe features. Al eerder behandeld in deze serie is deel 1 “Init Only Setters”, we gaan nu verder met “Pattern Matching”.

Om C# 9.0 te kunnen gebruiken dien je eerst de .NET 5 runtime of SDK te installeren. Ga hiervoor naar https://dotnet.microsoft.com/download. Na installatie zal C# 9.0 de standaard C# versie zijn bij elk nieuw project gebaseerd op .NET 5.

Waarom?

De syntax van ontwikkeltalen is al sinds jaren het onderwerp van discussies tussen ontwikkelaars. Leesbaarheid, efficiëntie en flexibiliteit is slechts een selectie van de tientallen argumenten die jouw mening vormen over het al dan niet geslaagd zijn van een syntax.
Martin Fowler geeft een – zoals we van hem gewend zijn – zeer zinvolle bijdrage in deze discussie met zijn bekende uitspraak:

Any fool can write code that a computer can understand.
Good programmers write code that humans can understand.

Met die uitspraak in het achterhoofd heeft Microsoft een aantal vereenvoudigingen aan de syntax van if en switch doorgevoerd.

Deze onderdelen worden door ons veel gebruikt om complexe condities uit te werken.
Sinds C# 7.0 helpt Pattern Matching ons om de code die we opleveren beter leesbaar en dus minder foutgevoelig te maken. Ook in C# 9.0 zijn er weer enkele nieuwe mogelijkheden toegevoegd.

Hoe?

Logical pattern

Om meer complexe condities goed leesbaar te houden is het logical pattern toegevoegd aan C# 9.0. Hiermee kunnen we gebruik maken van and, or en not in onze statements, en het herhalen van de parameter waarmee vergeleken moet worden kan achterwege worden gelaten.

blank

Dit is een krachtig mechanisme dat kan worden gebruikt in if-statements zoals in bijgaand voorbeeld. De volgorde waarin de controles worden uitgevoerd is volstrekt logisch, maar in sommige gevallen zul je toch aan deze volgorde moeten wennen. Vergeet dus niet om unittests toe te voegen met voldoende testsets om er zeker van te zijn dat je functie in alle gevallen het gewenste gedrag vertoont.

Het Logical pattern komt zelfs beter tot zijn recht wanneer dit wordt gecombineerd in switch expressions, zoals we hierna zullen zien bij het Relational Pattern.

Relational pattern

In C# 8.0 zijn switch expressions toegevoegd. Hiermee was het mogelijk om direct een returnwaarde als resultaat van een aantal voorwaarden te definiëren. De syntax bevatte veel onnodige herhalingen en was daarom nog niet in alle gevallen even leesbaar, zoals het onderstaande voorbeeld illustreert.

blank

In C# 9.0 kunnen we de bovenstaande syntax verder verfijnen door gebruik te maken van het Relational pattern. Hierdoor kunnen we rechtstreeks gebruik maken van relational operators zoals < of >=. Toepassing leidt tot het volgende resultaat:

blank

In deze syntax ligt de nadruk op de logica en het resultaat, en veel minder op het achterhalen van de juiste objecten.
We zien ook dat het gebruik van het Logical Pattern ook daadwerkelijk de leesbaarheid van de code vergroot: in één oogopslag is nu duidelijk dat er een selectie gemaakt wordt voor iemand tussen de 12 en 60.

Dit voorbeeld leent zich daarnaast om de switch expression, die in C# 8.0 al is geïntroduceerd nogmaals onder de aandacht te brengen.
Bij de switch expression staat de variabele vóór het switch keyword, de switch-onderdelen case en : zijn vervangen door de bekende =>. Als laatste is de body is geen statement meer, maar een expressie.
De expression is in het onderstaand voorbeeld uitgewerkt. Hierbij zien we dat we ons niet hoeven te beperken tot property checking, ook Type checking behoort tot de mogelijkheden.

blank

Type pattern

Met het type pattern kun je met een vereenvoudigde syntax conditie checks op type en properties uitvoeren . De nieuwe schrijfwijze in C# 9.0 is compact en overzichtelijk, zoals in onderstaand voorbeeld wordt getoond.

blank

Wanneer de parameter person niet van het type PersonRecord is ontstaat er geen exception maar wordt de evaluatie van het if-statement afgebroken. In het andere geval (person is van het type PersonRecord) wordt het resultaat bepaald op basis van de property Age van person.

Wees je er in dit voorbeeld goed van bewust dat deze code géén NullReferenceException oplevert wanneer de parameter person null is.

Verder?

Veel van onze logica in onze applicaties is vormgegeven door implementaties van if-then-else en switch statements. Na verloop van tijd kunnen deze constructies steeds complexer en onoverzichtelijker worden.
Met de nieuwe mogelijkheden kunnen we deze bestaande code relatief eenvoudig refactoren naar beter leesbare en dus beter onderhoudbare code.

Maar natuurlijk geldt zoals altijd: bedenk of deze complexe constructies gezien kunnen worden als code smell voor het overtreden van belangrijke SOLID principes, zoals het Open/Closed of Single Responsibility principe.
Overweeg in die gevallen vooral ook de toepassing van nette OO oplossingen, zoals het inzetten van encapsulation en de vele design patterns die beschikbaar zijn.

berglerC# 9.0 nieuwe features – Pattern Matching (2-4)
Lees meer

C# 9.0 nieuwe features – Init Only Setters (1-4)

C# 9.0 nieuwe features – Init Only Setters (1-4)

Init Only Setters

Met de komst van .NET 5 en C# 9.0 zijn er heel veel waardevolle toevoegingen gedaan aan de programmeertaal. In deze Blog serie zullen we inzoomen op een aantal belangrijke nieuwe features en we trappen af met “Init Only Setters”.

Om C# 9.0 te kunnen gebruiken dien je eerst de .NET 5 runtime of SDK te installeren. Ga hiervoor naar https://dotnet.microsoft.com/download. Na installatie zal C# 9.0 de standaard C# versie zijn bij elk nieuw project gebaseerd op .NET 5.

Waarom?

De Init Only Setters zijn aan C# toegevoegd om de ontwikkelaars een betere ervaring te geven met het maken en gebruiken van immutable classes of structs, door een extra moment te introduceren waarop data gemodificeerd mag worden.

Voorheen werd immutability verkregen door members readonly te maken of door properties niet te voorzien van een public setter. Het probleem wat hiermee ontstond, was dat je de data van het object alleen kon initialiseren via constructor parameters. Ook middels de in C# 3.0 geïntroduceerde object initializers, was het niet mogelijk om de data voor het object bij initialisatie in te stellen:

blank

Hoe?

In C# 9.0 is het nu wel mogelijk om immutable properties voor een object te initialiseren middels de object initializer. Die doe je door de setter van de property te vervangen door het nieuwe init keyword:

blank

Hiermee wordt dus voorkomen dat je expliciet constructor parameters voor alle properties moet aanmaken. Het geeft de ontwikkelaar dus veel vrijheid in het initialiseren van objecten.

Verder?

Het kunnen instellen van immutable properties middels de object initializer is verreweg het grootste voordeel wat de Init Only Setters feature biedt. De nieuwe feature kan echter breder ingezet worden, onder andere op de volgende manieren:

  • Setters van properties kunnen nu in de instance constructor van de afgeleide class ook benaderd worden:
    blank
  • Init Only Setters kunnen ook benaderd worden vanuit de body van een andere Init Only Setter:
    blank

Auteur: Patrick Vroegh © 2021 Bergler Competence Center

berglerC# 9.0 nieuwe features – Init Only Setters (1-4)
Lees meer

Bergler Technology Radar 2021

Bergler Technology Radar 2021

Ondanks dat de wereld door de pandemie sterk is veranderd en er veel tot stilstand is gekomen, gaan de veranderingen op het gebied van softwareontwikkeling onverminderd snel. Hierdoor blijft het als organisatie zaak om bij te blijven met de recente ontwikkelen. Belangrijk struikelblok is het aanbrengen van focus op de juiste topics. Wij proberen hier als ICT-dienstverlener organisaties mee te helpen, door gebruik te maken van onze kennis opgedaan bij veel verschillende opdrachtgevers. Hiervoor gebruiken wij de technology radar zoals is bedacht door trendwatchers van ThoughtWorks. Dit geeft een duidelijk overzicht van de trends welke aansluiten op onze visie binnen Bergler voor 2021.

Legenda

De technology radar is opgedeeld in 4 verschillende kwadranten. Dit zijn:

  • Techniques:
    Methodes en technieken welke van belang zijn voor verbeteringen gedurende een softwareontwikkelingstraject;
  • Platforms:
    Voor het bouwen en/of hosten van software projecten;
  • Tools:
    Voornamelijk gereedschap om het ontwikkelproces te verbeteren. Denk dan aan het inzichtelijker maken van code of processen binnen de code;
  • Languages-And-Frameworks:
    Welke ontwikkeltaal gebruik je en eventueel welk raamwerk daar bovenop?

Elk kwadrant is opgedeeld in 4 ringen die ons advies geven m.b.t. de research en development fase waarin een topic zich zou moeten bevinden. Voor ons als Bergler zijn alle topics die op onze technologie radar staan het waard om eens nader te bekijken en ze goed in de gaten te houden. De plek in de ringen zijn een algemene indicatie en dit kan per organisatie nog verschillen, afhankelijk van de businesscase. Het algemene idee achter de ringen is het volgende:

  • HOLD: Dit zijn topics met potentie welke wij goed in de gaten houden, maar die nog niet productierijp zijn, of schaduwkanten hebben die goed afgewogen moeten worden.
  • INVESTIGATE: Dit zijn topics die organisaties in ieder geval zouden moeten onderzoeken. Het zijn waardevolle tools, die productierijp zijn maar mogelijk niet voor elke organisatie dezelfde waarde toevoegen. Een goede impact analyse is aan te raden. (*)
  • TRY OUT: Dit zijn topics waarvan we adviseren om naast onderzoek ze ook actief op te nemen in proof of concepts en te beoordelen of en op welke wijze ze bij kunnen dragen aan de organisatie. (*)
  • ADOPT: Dit zijn topics waar de inzet direct wordt aanbevolen.

(*) Bepaalde topics hebben wij bewust niet in de “ADOPT” ring geplaats maar in één van de onderliggende ringen, ondanks dat het een volwassen topic betreft.  Dit kan zijn omdat zijn dat de impact van het implementeren veel impact kan hebben op b.v. de organisatiestructuur en/of werkwijze. Het is dan natuurlijk als organisatie van belang dit goed het overwegen voor men tot implementatie over gaat.

Verdieping

blankVoor alle topics welke wij in de Techradar hebben opgenomen hebben wij een verklarende tekst opgenomen. In veel gevallen zijn dit ook links naar eerder door Bergler georganiseerde sessies en of blogpost. Kijk hier voor een overzicht van de nog aankomende sessies.

We willen hier nog een aantal topics uit de technology radar uitlichten:

Threat Modeling

Wij zien Threat Modeling als een belangrijk onderdeel van een software ontwikkelingslifecycle. Door de gang naar de cloud wordt de attack surface vergroot. Hierdoor wordt het opnemen van security gerelateerde technieken in het ontwikkelproces van steeds groter belang. Threat Modeling is geen nieuwe maar wel een krachtige techniek om al vroeg in je ontwikkeltraject kwetsbaarheden te onderkennen. Wil je hier meer over weten schrijf je dan in voor ons webinar: Threat Modeling.

.NET 5

Met de komst van .NET 5 nadert het afscheid van het fullstack .NET framework. Dit heeft veel impact voor organisaties, het is niet aan te raden door te blijven ontwikkelen op de verouderde frameworks. Dit dwingt organisaties om na te denken over migratie strategieën. Wil je meer hierover weten schrijf je dan in voor ons webinar: Migratiepaden naar .NET 5.

C# 9

Het recent geïntroduceerde C# 9 geeft toegang tot nieuwe language features welke het ontwikkelen van code in C# kan vereenvoudigen.  Met Record Types worden immutable reference types op een eenvoudige manier geïntroduceerd.  Wil je meer hierover weten schrijf je dan in voor ons webinar: Value objects als records in C# 9.

Living Documentation

blankWij houden de ontwikkelingen op software development gebied nauw in de gaten. Wij als Bergler zullen onze Technology Radar dan ook bijwerken indien nodig. Blijf deze dus in te gaten houden of bezoek onze gratis webinars ter inspiratie. Mocht je meer willen weten van bepaalde topics dan kun je altijd contact met ons opnemen.

berglerBergler Technology Radar 2021
Lees meer

Jaarprogramma 2021

Jaarprogramma 2021

Jaarprogramma 2021

We kijken terug op een bewogen 2020. Toen we het competence center programma voor afgelopen jaar samenstelden gingen we uit van gezellige sessies op kantoor en in Houten. Hoe anders is de praktijk gelopen. Gelukkig hebben we afgelopen jaar gezien dat we ook online hele toffe sessies konden organiseren. De kennis sessies in Houten werden online sessies via YouTube, en met veel succes want aan het einde van het jaar hadden we maar liefst 450 aanmeldingen voor onze sessies over Docker en Kubernetes. Dat had in de ruimte in Houten nooit gepast. Ook de interne opleidingen kregen een ander karakter waarbij we op het ene scherm de Team sessie actief hadden om op het andere scherm de opdrachten uit te voeren. Iets minder persoonlijk, maar zeker werkzaam.

Zoals elk jaar hebben we samen met het team van Lead developers gekeken naar de thema’s die we dit komende jaar willen behandelen. Daarnaast is er nieuws op het vlak van ons opleidingsprogramma: komend jaar faciliteren we voor alle medewerkers een Pluralsight abonnement waar we onze doelen uit het opleidingsprogramma in opnemen. Je kunt dan denken aan zaken als SOLID development, automatisch testen, maar ook het opkrikken van algemene C# kennis. We verwachten dat we hiermee een hele mooie toevoeging doen aan het ondersteunen van onze software developers. Meer informatie volgt in de loop van het eerste kwartaal. Dan nu de thema’s voor het Competence Center programma van 2021:

Migratiepaden naar .NET 5

blankMet de komst van .NET 5 beweegt Microsoft voor het eerst in de geschiedenis definitief weg van het fullstack .NET framework. De nieuwe versie is gebaseerd op .NET Core. Wat betekent dit voor bestaande producten en welke strategieën zijn er om te migreren? Op deze vragen gaan we samen in.

Azure DevOps

blankWe hebben de afgelopen jaren al best wat aandacht besteed aan Azure DevOps. Tegelijk gaan de ontwikkelingen van dit platform erg hard, en hebben we gemerkt dat er bij collega’s behoefte is om eens stil te staan bij zaken waar je in het dagelijks werk misschien niet altijd tegenaan loopt. Enerzijds nog eens wat dieper in Git duiken, maar vooral ook kijken naar de CI/CD pipelines en planningen.

Een introductie in gRPC

blankEen van de technologieën die is geïntegreerd in .NET Core is gRPC. Omdat dit protocol een prima alternatief is voor de WCF services die niet meer beschikbaar zijn in .NET Core, is er alle reden om deze technologie te bestuderen.

Een introductie in Blazor

blankMet de komst van Blazor introduceert Microsoft haar visie op single page front-end development op basis van C#. Hierbij wordt gebruik gemaakt van web assembly, een standaard van W3C die door alle grote browsers ondersteund wordt. We zullen zeker stilstaan bij de roerige wereld van de front-end development en welke strategie hier het beste bij past. Duidelijk is in ieder geval dat er een risico is dat in de front-end weer monolitische applicaties ontstaan die in de toekomst lastig te onderhouden zijn. Hoe verhoudt Blazor zich in dit speelveld en hoe kun je ook in de front-end met deze technologie kleine micro clients maken die samen toch als één applicatie voelen.

blank

Bergler hackaton

Juist omdat we elkaar het laatste jaar zo weinig hebben gezien, is het idee ontstaan om komend jaar eens iets nieuws te proberen. Op zaterdag 29 mei organiseren we een hackaton waar onze collega’s op een leuke manier nieuwe technieken kunnen uitproberen, gezellig samen kunnen komen en voor de eeuwige developer roem mogen strijden. Ik hoop dat dit een groot succes mag worden en dat we nog vele soortgelijke events mogen organiseren.
blank

… En nog veel meer

Los van de bovenstaande hoofdthema’s worden er nog vele kleinere sessies georganiseerd. Voor het volledig programma verwijs ik graag naar onze flyer.

Met vriendelijke groet,
Menno Jongerius

berglerJaarprogramma 2021
Lees meer

Authenticatie in ASP .NET Core 3.1

Authenticatie in ASP .NET Core 3.1

Authenticatie in ASP .NET Core 3.1

Authenticatie en autorisatie worden vaak in één adem genoemd en zijn in zekere zin ook onlosmakelijk aan elkaar verbonden. Toch hebben ze ieder hun specifieke verantwoordelijkheid. Met behulp van authenticatie kunnen gebruikers van een webapplicatie zich identificeren om toegang te krijgen tot de applicatie. Met autorisatie kunnen ze toegang krijgen tot specifieke functies en functionaliteit van een webapplicatie.

ASP.NET Core Identity is een zogenaamd membership system dat gebruikt wordt bij het bouwen van ASP.NET Core-webapplicaties, inclusief lidmaatschap, inloggen en gebruikersgegevens. ASP.NET Core Identity maakt het mogelijk om inlogfuncties toe te voegen aan een webapplicatie en maakt het eenvoudig om gegevens over de ingelogde gebruiker toe te passen.

ASP.NET Core Identity maakt authenticatie voor één enkele applicatie mogelijk. Het heeft zoals aangegeven redelijk wat features “out-of-the-box”. Wanneer je authenticatie op een meer gecentraliseerde en geïsoleerde manier wilt gebruiken voor meerdere client applicaties is het beter te kijken naar een token service met OAuth 2.0 and OpenID Connect implementatie zoals IdentityServer.

In dit artikel wordt één van de manieren beschreven waarop binnen ASP.NET Core 3.1 authenticatie kan worden geregeld met behulp van Identity Core. Het uitgebreidere IdentityServer behoort niet tot de scope van dit artikel.

De volgende items zullen aan de orde komen:

  • Opzetten ASP.NET Core Identity framework (EF Core 3.1 & migrations)
  • Registratie van nieuwe gebruikers
  • In-/uitloggen van gebruikers
  • Account Lockout mechanisme
  • Custom validatie naast de al in Identity aanwezige default validatie

Opzetten ASP.NET Core Identity framework

Er bestaan in Visual Studio diverse templates die kunnen worden gebruikt bij het opzetten van een Identity Core framework. In alle gevallen is de basis een context die is afgeleid van IdentityDbContext. Dit is de base class voor de EF Core database context die gebruikt wordt voor Identity en waaraan het User objecttype wordt meegegeven:

blank

In de OnModelCreating methode kan een verdere configuratie van de objecten plaatsvinden zoals het verplicht maken van velden of het initiëren van de tabellen met bepaalde default data.

Daarnaast is in bovenstaande code snippet een DbSet aangemaakt die gebruikt gaat worden als IdentityUser object (en die is afgeleid van de IdentityUser base class).

Het registreren van de Identity DB context service en de setup voor het gebruik van (in dit geval) SQL Server gebeurt in de ConfigureServices methode van startup.cs:

blank

Na het uitvoeren van de diverse EF Core migration commando’s is er in SQL Server een Identity database aangemaakt met daarin een aantal standaard Identity tabellen (welke allemaal de prefix ‘AspNet’ hebben):

blank

In de volgende paragrafen zullen de betekenis en functie van diverse velden uit m.n. de AspNetUsers tabel verder aan de orde komen. Voor dit artikel zijn de volgende tabellen en hun onderlinge relatie van belang:

blank

Om de Identity Core functionaliteit beschikbaar te maken in de applicatie zijn tot slot twee zaken nodig in de startup.cs:

  1. Het registreren van de services voor het ASP.NET Core Identity framework (in de ConfigureServices methode):
    blank
  1. Het toevoegen van de authenticatie middleware (in de Configure methode):
    blank

Registratie van nieuwe gebruikers

Om nieuwe Identity Users te registreren wordt gebruik gemaakt van de UserManager class. Deze class bevindt zich in de namespace Microsoft.AspNetCore.Identity en wordt d.m.v. dependecy injection in een controller geïnjecteerd:

blank

Om een nieuwe gebruiker te registreren is het noodzakelijk naast een gebruikersnaam en/of emailadres ook een wachtwoord op te geven. Met behulp van deze gegevens kan een gebruiker door de applicatie geauthentiseerd worden.

Er kan m.b.t. authenticatie gekozen worden voor de combinatie gebruikersnaam/wachtwoord of emailadres/wachtwoord. Wanneer voor de laatste optie wordt gekozen is het aan te raden tijdens het registreren van de services voor het ASP.NET Core Identity framework de optie mee te geven dat gevalideerd moet worden dat het emailadres van de nieuw toe te voegen Identity User uniek is (User.RequireUniqueEmail = true).

Voor de eerste optie geldt by design dat het Identity framework valideert dat de gebruikersnaam van de nieuw toe te voegen Identity User uniek is.

Registratie gebeurt vervolgens in een POST action in de controller:

blank

De return value van deze (async) functie is van het type IdentityResult en bevat een boolean flag Succeeded die aangeeft of de actie geslaagd is of niet. Indien de actie niet succesvol was bevat de property Errors de fout(en) die is/zijn opgetreden bij de CreateAsync actie.

Het wachtwoord wordt (indien de operatie succesvol was) volgens een hashing algoritme encrypted opgeslagen in de database. Daarnaast worden enkele velden automatisch gevuld zoals het NormalizedUserName en het NormalizedEmail veld.

In-/uitloggen van gebruikers

Zoals aangegeven worden gebruikers geauthentiseerd op basis van een gebruikersnaam/wachtwoord of emailadres/wachtwoord combinatie. Het ASP.NET Core Identity framework biedt hiervoor twee mogelijkheden die ieder een verschillend doel dienen:

  1. CheckPasswordAsync

Deze methode hasht het opgegeven wachtwoord en vergelijkt het met de bestaande wachtwoordhash (zoals dat bijvoorbeeld is opgeslagen in de database)

  1. PasswordSignInAsync

Deze methode doet naast het controleren van het wachtwoord veel meer:

  • Controleert of inloggen is toegestaan. Als de gebruiker bijvoorbeeld een bevestigde e-mail moet hebben voordat hij zich mag aanmelden, retourneert de methode Failed
  • Roept UserManager.CheckPasswordAsync op om te controleren of het wachtwoord correct is. Wanneer een mislukte inlogpoging (wachtwoord is niet correct en de Lockout optie is enabled) het geconfigureerde maximum aantal mislukte aanmeldingspogingen overschrijdt wordt het account van de gebruiker geblokkeerd
  • Als de optie two-factor authentication is ingeschakeld voor de gebruiker, stelt deze methode de cookie in en retourneert TwoFactorRequired
  • Maakt een ClaimsPrincipal aan en persisteert dit via een cookie

 

Wanneer bevestigde e-mails en lockout geen vereiste zijn dan volstaat het om de CheckPasswordAsync methode uit de UserManager class te gebruiken. De SignInManager class is gekoppeld aan de cookie-authenticatie.

De volgende code snippet toont een manier om door middel van emailadres/wachtwoord combinatie authenticatie van een gebruiker te doen:

blank

Analoog aan bovenstaande code snippet kan een gebruiker worden geauthentiseerd via zijn/haar gebruikersnaam.

In de volgende paragraaf wordt uitgebreider ingegaan op het Lockout mechanisme waarmee restricties kunnen worden gesteld aan het aantal pogingen dat een gebruiker mag doen om zichzelf bij een applicatie te authentiseren.

Account Lockout mechanisme

Het ASP.NET Core Identity framework biedt standaard een aantal belangrijke beveiligingsfuncties die het authenticatieproces van extra checks te voorzien. Denk hierbij aan:

  • Two-Factor Authentication (met behulp van SMS of email)
  • Account Lockout
  • Account Confirmation

Account Lockout is een belangrijke functie van het ASP.NET Core Identity framework. Het blokkeert het account van de gebruiker als deze een bepaald aantal keren een verkeerd wachtwoord invoert. Dit kan worden gespecificeerd door het maximale aantal mislukte pogingen (default 5x) en de lockout-tijd (default 5 minuten) te configureren in startup.cs:

blank

De volgende code snippet toont het gebruik van het Lockout mechanisme: een mogelijkheid om het aantal inlogpogingen te beperken tot een opgegeven maximum. Zoals in de vorige paragraaf aangegeven is het hiervoor noodzakelijk gebruik te maken van de SignInManager.PasswordSignInAsync methode. Door de parameter lockoutOnFailure te activeren (true), wordt de lockout-functionaliteit ingeschakeld.

blank

Custom validatie

Naast de standaard al aanwezige validatie in het ASP.NET Core Identity framework is het mogelijk eigen validatie toe te voegen zoals bijvoorbeeld het controleren op emaildomein of het uitsluiten van de mogelijkheid dat gebruikersnaam en wachtwoord identiek zijn. De volgende code snippets tonen enkele mogelijke custom validatie’s.

blank

Het opnemen van de (extra) custom validatie’s gebeurt in startup.cs:

blank

Auteur: Pieter Baart © 2020 Bergler Competence Center

berglerAuthenticatie in ASP .NET Core 3.1
Lees meer