I kapitel 7, "Håndtering af datoer, tid og internationalisering", lærte du om arbejdet med datoer, tid, tidszoner og hvordan du globaliserer og lokaliserer en .NET-kodebase. I denne sektion vil vi fokusere på, hvordan du kan lokalisere en webside, der bruger ASP.NET Core, både med henblik på strenglokalisering og globalisering af data som datoer og valutaer.
Når du lokaliserer en webapplikation, handler det ikke kun om at oversætte tekstindhold, men også om at tilpasse den kulturelle kontekst for at sikre, at brugeroplevelsen føles naturlig og korrekt for forskellige geografiske områder og sproggrupper. Du kan for eksempel bruge IStringLocalizer til at lokalisere strengværdier og IHtmlLocalizer til at lokalisere HTML-værdier. Det er dog vigtigt at bemærke, at HTML-struktur normalt bør være den samme på tværs af lokaliteter, da det er indholdet, der skal tilpasses. For visninger kan du bruge IViewLocalizer.
Oprettelse af ressourcefiler
Lad os først oprette ressourcefiler til at lokalisere brugergrænsefladen på flere sprog, herunder amerikansk engelsk, britisk engelsk og fransk. For at gøre dette, skal du først oprette en mappe til ressourcerne i din projektstruktur. I Visual Studio kan du gøre dette som følger:
-
I dit ASP.NET Core-projekt, opret en ny mappe kaldet
Resources. Dette er standardmappen, som lokaliseringsservices ser i efter*.resx-resursefiler. -
I
Resources-mappen, opret en ny undermappe kaldetViews. -
I
Views-mappen, opret en ny undermappe kaldetHome.
Nu er vi klar til at oprette ressourcefilerne.
I Visual Studio 2022
-
I
Home-mappen, opret en ny ressourcefil kaldetIndex.en-US.resx. -
Brug ressourcefilredigeringsværktøjet til at definere navne og værdier for de forskellige lokaliserede etiketter.
-
Kopiér og indsæt filen og omdøb den til
Index.en-GB.resxog ændr værdierne, hvor det er nødvendigt, for at skelne mellem amerikansk og britisk engelsk. -
Fortsæt på samme måde for at oprette franske versioner af ressourcefilerne:
Index.fr-FR.resxogIndex.fr.resx, og tilpas værdierne til fransk sprog og kultur.
I Visual Studio Code
-
I
Home-mappen, opret en ny fil kaldetIndex.en-US.resx. -
Rediger indholdet af denne fil, så den indeholder de engelske værdier, som f.eks. virksomhedens navn, land, antal varer, bestillingsdato osv.
-
Kopiér filen og omdøb den til
Index.en-GB.resx, og ændr værdierne til britisk engelsk, som f.eks. ændre USA til Storbritannien. -
Opret franske versioner af filerne som beskrevet ovenfor.
Lokalisering af Razor-visninger
Når ressourcefilerne er oprettet, kan vi begynde at lokalisere Razor-visningerne. Dette kræver, at vi importerer et specifikt navnerum for lokaliseringsarbejde og injicerer IViewLocalizer-servicen i vores visning.
I Views/Home/Index.cshtml gør vi følgende:
-
Importer navnerummet for lokaliseringsarbejde:
-
Ændr visningens model og brug lokaliseringsnøglerne til at vise de lokaliserede værdier:
Konfiguration af lokaliseringsservices
For at gøre det muligt at håndtere forskellige lokaliteter og kulturer, skal vi konfigurere ASP.NET Core til at understøtte de ønskede sprog- og kulturopsætninger. Dette gøres i Program.cs-filen:
-
Før opkaldet til
AddControllersWithViews, skal vi tilføje konfigurationen for lokaliseringsservices og angive stien til ressourcemapperne: -
Efter opkaldet til
Build-metoden iProgram.cs, deklarer de kulturer, du vil understøtte. For eksempel kan vi understøtte amerikansk engelsk, britisk engelsk, neutral fransk og fransk i Frankrig:
Med denne konfiguration vil webapplikationen kunne vise data i den ønskede kultur, som f.eks. datoformater og valuta, samtidig med at brugergrænsefladen lokaliseres.
Implementering af browserens sprogindstillinger
Når du har konfigureret din webapplikation til at understøtte flere kulturer, kan brugerne vælge deres foretrukne kultur. Dette kan gøres ved at tilføje en parameter til URL’en, sende en cookie eller angive en HTTP-header, som browseren sender med anmodningen.
I Chrome kan du for eksempel navigere til Indstillinger og søge efter sprogindstillinger. Hvis du bruger en lokaliseret version af Chrome, vil du muligvis skulle søge på dit eget sprog, såsom "språk" på svensk eller "idioma" på spansk.
Ved at konfigurere ASP.NET Core til at håndtere sådanne forespørgsler, kan du sikre, at applikationen vises korrekt i henhold til brugerens sprogpræferencer og den relevante kultur.
Det er vigtigt at forstå, at lokaliseringsarbejde ikke kun handler om oversættelse. Det indebærer at tage højde for kulturelle forskelle i format, skrift, og hvordan data som datoer, valutaer og adresser vises. Udover at oversætte tekst, skal du sikre dig, at din applikation fungerer korrekt i forskellige kulturer ved at tilpasse disse formater.
Hvordan måle ydeevne og håndtere samtidige opgaver i .NET?
Når vi arbejder med ydeevneoptimering i programmering, er det nødvendigt at anvende de rette værktøjer til at sammenligne forskellige metoder og teknikker. En af de mest anvendte teknikker til at benchmarke ydeevne i .NET-verdenen er BenchmarkDotNet. Denne værktøj gør det muligt at måle og analysere, hvordan forskellige koder fungerer med hensyn til tidsforbrug og ressourceudnyttelse.
I et simpelt eksempel som at sammenligne string concatenation og brug af StringBuilder, kan vi få indsigt i, hvordan små optimeringer kan have stor betydning for ydeevnen i store applikationer. Når vi kører benchmark-tests, vil resultaterne vise, hvordan en specifik metode præsterer sammenlignet med en anden.
For eksempel, når vi tester string-konkatenering og StringBuilder i et .NET 7.0 miljø, får vi resultater som:
-
String-konkatenering tager et gennemsnit på 412.990 nanosekunder.
-
StringBuilder tager et gennemsnit på 275.082 nanosekunder.
Dette viser ikke blot en tidsforskel, men også en forskel i konsistens. StringBuilder er langt mere stabil og konsekvent i sine målinger, mens string-konkatenering kan have større variationer, hvilket kan være kritisk, hvis programmet kører mange iterationer. Når man arbejder med store datamængder eller højhastighedsapplikationer, vil denne forskel i præstation kunne have en mærkbar effekt.
En vigtig bemærkning ved sådanne tests er håndteringen af outliers. Hvis din test viser usædvanlige eller ekstreme resultater, er det vigtigt at bemærke, hvordan disse outliers kan påvirke gennemsnittet og analysen. For eksempel, i ovenstående tests, blev der fjernet syv outliers for string-konkatenering og kun to for StringBuilder. Dette indikerer, at string-konkatenering er mere følsom overfor ydre faktorer, som kan forårsage uforudsigelige resultater.
Når man arbejder med samtidige opgaver, er det også nødvendigt at forstå, hvordan man kan køre flere opgaver parallelt for at forbedre ydeevnen. Dette kan gøres effektivt ved at anvende asynkrone metoder i .NET. I et eksempel, hvor tre metoder skal køres samtidig (hvor den første tager 3 sekunder, den anden 2 sekunder, og den sidste 1 sekund), kan asynkrone opgaver reducere den samlede ventetid, da alle opgaverne kan køre samtidigt, i stedet for at vente på, at én opgave afsluttes før den næste starter.
Før man begynder at køre opgaver asynkront, kan man dog teste ydeevnen synkront. For at gøre dette, kan man lave et simpelt program, hvor man simulerer tre metoder, der hver tager forskellig tid at fuldføre. Den synkrone metode vil se ud som følger:
-
Metode A kører og tager 3 sekunder.
-
Metode B kører og tager 2 sekunder.
-
Metode C kører og tager 1 sekund.
Den synkrone kørsel betyder, at programmet skal vente på, at Metode A afsluttes, før Metode B begynder, og derefter vente på Metode B, før Metode C kan startes. Den samlede tid for at køre alle tre opgaver vil være summen af de individuelle tider, hvilket resulterer i 6 sekunder.
For at forbedre ydeevnen kan man derimod vælge at køre metoderne parallelt. Dette kan gøres ved hjælp af asynkrone opgaver, hvilket betyder, at alle tre metoder kan køre samtidigt, og dermed reducere den samlede ventetid til 3 sekunder i stedet for 6. I dette scenario vil man bruge metoder som Task.WhenAll() eller Task.Run() for at sikre, at alle opgaver kører simultant.
Et godt eksempel på dette kunne være at anvende Thread.Sleep() til at simulere, at metoderne tager tid, og derefter bruge asynkrone opgaver til at køre disse metoder samtidigt.
I praksis er det nødvendigt at overveje flere faktorer, når man arbejder med asynkron programmering. For eksempel skal man være opmærksom på, hvordan tråde håndteres i .NET, samt hvilke metoder og teknikker der er mest effektive for ens specifikke applikation. Asynkrone opgaver kan føre til betydelige forbedringer i ydeevnen, men det er vigtigt at forstå, hvornår og hvordan man skal anvende dem korrekt for at undgå fejl og ineffektivitet i koden.
Når vi sammenligner synkrone og asynkrone metoder, er det tydeligt, at asynkrone opgaver kan give en markant forbedring i ydeevnen, især når det drejer sig om at køre mange uafhængige opgaver samtidig. Det er dog vigtigt at forstå, at ikke alle opgaver nødvendigvis vil drage fordel af asynkron kørsel, og at der kan være scenarier, hvor synkrone metoder er tilstrækkelige.
Endvidere bør man være opmærksom på, at asynkrone metoder ikke kun forbedrer ydeevnen i forhold til tid, men også i forhold til ressourceudnyttelse. Ved at udnytte samtidighed kan en applikation køre flere opgaver uden at blokere for andre processer, hvilket fører til en mere effektiv anvendelse af systemressourcer.
Det er også vigtigt at bemærke, at den samlede ydeevne ikke kun afhænger af, hvordan opgaverne er organiseret, men også af hardware-konfigurationen, hvilket er grunden til, at det altid er en god idé at køre flere tests og målinger under forskellige betingelser for at få et klart billede af, hvordan ens applikation præsterer.
Hvordan Opbygger Man Opkald og Synkronisering af Opgaver i C#?
I moderne applikationer er håndtering af samtidige opgaver en nødvendighed for at sikre effektiv udnyttelse af ressourcer og øge ydeevnen. C# tilbyder flere måder at oprette, synkronisere og arbejde med samtidige opgaver. I denne del vil vi dykke ned i, hvordan man arbejder med opgaver, synkronisering af ressourcer og hvordan man sikrer, at koden er trådsikker.
En grundlæggende teknik i C# til at starte opgaver er at bruge Task-klassen. I eksemplet herunder starter vi en opgave, der kører en anden opgave. Dette er nyttigt, når du har behov for at håndtere en proces, der skal køre parallelt med andre opgaver:
I dette tilfælde starter OuterMethod den indre opgave InnerMethod. Når OuterMethod er færdig med sin eksekvering, betyder det ikke nødvendigvis, at InnerMethod også er afsluttet. Faktisk kan konsolapplikationen afsluttes, før InnerMethod er begyndt, da OuterMethod ikke venter på, at InnerMethod bliver færdig.
For at sikre, at den indre opgave afsluttes før den ydre, skal vi knytte den til den ydre opgave ved hjælp af en speciel option:
Med denne ændring venter den ydre opgave på, at den indre opgave afsluttes, før applikationen stopper:
Når du arbejder med opgaver, kan der opstå situationer, hvor du har en metode, der skal være asynkron, men ikke nødvendigvis returnerer en opgave. I sådanne tilfælde kan du bruge Task.FromResult, Task.FromException eller Task.FromCanceled metoderne til at oprette en opgave, der allerede er afsluttet. Dette kan være nyttigt, når du implementerer en grænseflade, der kræver asynkrone metoder, men den underliggende metode er synkron.
Her er et eksempel, hvor du bruger Task.FromResult til at oprette en opgave, der returnerer et resultat:
Ovenstående metode simulerer et asynkront kald, men det er synkront, da det ikke nødvendigvis kræver nogen virkelig asynkron operation, men det giver dig mulighed for at arbejde med en grænseflade, der forventer en opgave.
Når man arbejder med samtidige opgaver, er en vigtig faktor at sikre trådsikker adgang til delte ressourcer. Når flere tråde forsøger at få adgang til en delt ressource, kan der opstå race conditions, hvor den ene tråd overskriver en andens ændringer. For at undgå dette skal du sikre, at kun én tråd har adgang til ressourcen ad gangen. En enkel måde at implementere trådsikker adgang er ved hjælp af en flagmekanisme, der fungerer som et trafiklys.
Tænk på det som i William Goldings "Fluernes Herre", hvor karaktererne Piggy og Ralph anvender en muslingeskal til at kalde et møde og pålægger en regel om, at kun den, der holder muslingen, kan tale. På samme måde fungerer et flag som "muslingen", hvor kun én tråd kan få adgang til den delte ressource ad gangen.
I C# kan du bruge Monitor eller Interlocked til at sikre synkronisering. Monitor giver dig mulighed for at kontrollere, om en tråd skal få adgang til en delt ressource, mens Interlocked giver dig mulighed for at manipulere simple numeriske typer på CPU-niveau.
Et praktisk eksempel på synkronisering af opgaver og adgang til delte ressourcer kan se sådan ud:
Når du kører opgaverne parallelt, kan du opleve et resultat, der ser ud som følger:
Det er vigtigt at forstå, at når du arbejder med samtidige opgaver, er der mange nuancer, der kræver opmærksomhed. Udover den synkronisering, som er blevet præsenteret her, bør du overveje, hvordan fejl håndteres i asynkrone metoder og hvordan du kan bruge undtagelseshåndtering til at sikre, at applikationen ikke går ned, hvis noget går galt under kørsel. Desuden er det også væsentligt at forstå forskellen mellem "fire and forget" opgaver og opgaver, der skal vente på afslutning, da begge metoder kræver forskellig håndtering for at undgå utilsigtet adfærd eller fejl.
Hvordan forbedrer async og await multitasking på serversiden, og hvilke almindelige typer understøtter dette?
Brugen af async og await i serversideprogrammering har til formål at øge effektiviteten ved at frigøre dyrebare I/O-tråde, så de ikke sidder fast i ventetilstand på langsigtede opgaver. I stedet oprettes billigere arbejdstråde, der venter på, at disse opgaver bliver færdige, hvilket øger serverens evne til at håndtere flere klientanmodninger samtidig. Denne form for multitasking forbedrer skalerbarheden af webapplikationer og -tjenester betragteligt, da flere brugere kan serviceres parallelt uden at blokere kritiske ressourcer.
Mange almindelige typer i .NET-økosystemet understøtter asynkrone metoder, der kan anvendes med await. Eksempler på sådanne typer omfatter DbContext og DbSet, der har metoder som AddAsync, FindAsync og SaveChangesAsync, HttpClient med GetAsync, PostAsync og SendAsync, samt StreamReader og StreamWriter, som har henholdsvis ReadAsync og WriteAsync metoder. Når man ser en metode med Async-suffikset, bør man undersøge, om den returnerer en Task eller Task<T>, hvilket indikerer, at den kan anvendes asynkront sammen med await, og metoden der kalder den skal være markeret med async.
Siden introduktionen af async og await i C# 5 har sproget udviklet sig, så det nu også er muligt at anvende await i catch-blokke. Det muliggør bedre fejlhåndtering i asynkrone programmer ved at lade kode vente på afslutningen af asynkrone operationer, selv under undtagelsesbehandling.
Forståelsen af multitasking i .NET kræver også kendskab til, hvordan man korrekt definerer og starter opgaver, venter på deres færdiggørelse, kontrollerer deres afslutningsrækkefølge og synkroniserer adgang til delte ressourcer. Disse koncepter er fundamentale for at skrive effektive og skalerbare applikationer.
Ud over de grundlæggende asynkrone metoder findes der også en bred vifte af tredjepartsbiblioteker, som udvider funktionaliteten og gør arbejdet lettere eller mere effektivt. Disse inkluderer blandt andet ImageSharp til billedbehandling, Serilog til logging, AutoMapper til objektafbildning, FluentAssertions og FluentValidation til henholdsvis enhedstest og datavalidering samt QuestPDF til generering af PDF-filer. Valget af bibliotek bør baseres på både popularitet og relevans for det konkrete udviklingsbehov, og mange af disse biblioteker er aktive i open source-miljøet, hvilket sikrer vedvarende opdateringer og forbedringer.
Det er vigtigt at forstå, at async og await ikke blot er syntaktisk sukker, men fundamentale redskaber til at bygge moderne serverapplikationer, der kan håndtere mange samtidige forbindelser uden at ofre ydeevne. Man skal dog være opmærksom på korrekt brug af synkronisering, undgå unødvendige låse og foretrække atomare operationer via Interlocked-klassen, når det er muligt, for at undgå trådblokering og dødlås. I situationer med kompleks trådsikkerhed kan Mutex anvendes som et kraftigere værktøj til styring af kritiske sektioner.
Det er ligeledes væsentligt at forstå, hvordan man kan aflyse opgaver ved hjælp af cancellation tokens, hvilket giver bedre kontrol over langvarige asynkrone operationer og hjælper med at frigøre ressourcer hurtigt, når en opgave ikke længere er nødvendig.
Async-programmering forbedrer ikke kun serverens kapacitet men understøtter også en bedre brugeroplevelse, hvor responstider holdes lave, og applikationer forbliver responsive, selv under høj belastning. Den moderne udvikler bør derfor mestre disse teknikker og forstå de bagvedliggende principper for at kunne udnytte dem optimalt.
Hvordan implementere AutoMapper-konfigurationer og enheds-testning i .NET
Når man arbejder med AutoMapper i .NET, er det vigtigt at sikre sig, at konfigurationen er korrekt opsat og at tests udføres for at bekræfte, at mapperen fungerer som forventet. Dette gælder især, når vi håndterer modeller, der skal mappe komplekse objekter til simplere view-modeller, som f.eks. i forbindelse med en shopping cart og dens opsummering i en applikation.
Et grundlæggende scenarie er at bruge AutoMapper til at omdanne data fra et shopping cart-objekt til en opsummeringsmodel, som præsenterer en kunde og deres købsinformation på en forenklet måde. Her vil vi gennemgå et eksempel på, hvordan man opretter en sådan konfiguration og tester dens funktionalitet.
Først opretter vi en AutoMapper-konfiguration i et mapper-projekt, hvor vi definerer, hvordan data fra én model skal kortlægges til en anden. I et typisk tilfælde, som det der beskrives her, kan vi have et modelobjekt som en Cart, der indeholder detaljer som kundens navn og købte varer. Vi ønsker at mappe disse data til et simpelt Summary-view-model, der viser kundens navn og det samlede beløb for købet.
Når vi har konfigureret mapperen og kører en test, vil vi ofte opleve, at nogle medlemmer af den destination model, som f.eks. den samlede pris, ikke er mappet korrekt, hvilket kan føre til en fejlinformation i resultatet. Dette kan korrigeres ved at tilføje specifikke mapping-regler for de relevante medlemmer.
For eksempel, når testen fejler på grund af en Total-værdi, der ikke er mappet, kan vi tilføje en specifik regel for at beregne summen af varernes priser og opdatere konfigurationen med noget som følgende:
Med denne justering kan vi sikre, at Total-feltet bliver korrekt beregnet og mappet fra Cart-modellen til Summary-modellen.
Når konfigurationen er korrekt, og mapperen er oprettet, kan vi derefter bruge denne i en live-applikation, som for eksempel et konsolprogram. I et sådant program kan vi oprette et eksempel på en Cart, fyldt med varerne, og derefter bruge AutoMapper til at omdanne det til en opsummering af kundens køb.
Eksempelvis:
Når man kører dette konsolprogram, vil man få output som viser, at "John Smith" har brugt 8,86 USD. Dette bekræfter, at konfigurationen og mappingen fungerer korrekt.
Når man arbejder med AutoMapper, er det også vigtigt at forstå, hvordan man håndterer testning, især enhedstests. En effektiv måde at skrive tests på er ved at bruge FluentAssertions, som giver en mere naturlig læsning af assertion-udtryk i testene. Ved hjælp af FluentAssertions kan man for eksempel let teste, om en streng opfylder visse krav:
På samme måde kan man lave tests for samlinger eller datoer ved at bruge samme fluent API. For eksempel kan vi teste, at en samling kun indeholder elementer af en bestemt længde:
En vigtig pointe ved brug af AutoMapper og enhedstests i .NET er, at disse værktøjer, selvom de forenkler arbejdet, ikke eliminerer behovet for grundig fejlfinding og forståelse af, hvordan data flyder gennem applikationen. Det er essentielt at forstå, hvordan mapperen konfigureres, og hvordan man validerer resultaterne med passende tests. For at kunne diagnosticere problemer effektivt, kan det være nødvendigt at bruge avancerede features i AutoMapper og enheds-testbibliotekerne, og at have en god forståelse for, hvordan disse kan kombineres for at sikre applikationens korrekthed.
Hvad sker der, når videnskab og spekulation mødes? Historien om Biggs' eksperimenter med planter
Hvordan Kan Vi Forhindre Den Ødelæggende Effekt Af Konspirationsteorier På Samfundets Tillidsnetværk?
Hvordan udgiver man sin egen bog i dagens forlagssystem?
Hvordan man opbygger muskelmasse i Off-Season: Strategier og Principper
Hvilke udfordringer står vi overfor i udviklingen af chalcogenid solceller?

Deutsch
Francais
Nederlands
Svenska
Norsk
Dansk
Suomi
Espanol
Italiano
Portugues
Magyar
Polski
Cestina
Русский