Nieuw in .NET Core 3.0

Tech Burst geschreven door Vincent Bitter

In juni 2016 bracht Microsoft .NET Core 1.0 uit, daarna 1.1 in november 2016, gevolgd door versie 2.0 in augustus 2017 en 2.1 in mei 2018. De laatste final release was .NET Core 2.2 in december 2018. En nu staat de volgende major release voor de deur: .NET Core 3.0, in de tweede helft van 2019. De specifieke datum zal bekend gemaakt worden tijdens de Build 2019 in mei 2019. Gelukkig hoeven we niet te wachten, want er zijn al een aantal preview versies beschikbaar! Sterker nog, de eerste preview van .NET Core 3.0 is tegelijk met de final versie van .NET Core 2.2 verschenen in december 2018. Dit artikel is gebaseerd op .NET Core Preview3 en beschrijft de nieuwe features zoals beschreven in de release notes


Desktop development: Forms and WPF

Dit meen je niet? Het old-school Windows Forms als onderdeel van een hagelnieuw, open-source .NET Core development platform? Nee, dit is geen grap, maar zelfs de belangrijkste feature van de nieuwe .NET Core release. Betekent dit dan dat .NET Core niet langer cross-platform is, of zijn Windows Forms en WPF naar platformen als Linux en Mac omgebouwd? Nou, het is nog verwarrender, want beide zijn niet waar. .NET Core blijft cross-platform, maar de Forms en WPF features worden alleen op Windows ondersteund via de zogenaamde Windows Desktop Packs. Deze set van libraries hebben onder andere volledige toegang tot de Windows 10 API’s. Naast Windows 10 API’s, is het ook mogelijk om COM API’s en WinRT API’s aan te roepen. Hierdoor kun je volledig integreren met het Windows ecosysteem.

Maar je kunt al code delen tussen .NET Framework en .NET Core door .NET Standard libraries te gebruiken, dus waarom zou je de moeite nemen om je applicaties om te bouwen naar .NET Core?

De grootste voordelen van .NET Core voor desktop applicaties:
1. Gebruik een specifieke versie van .NET Core (side-by-side en app-local).
2. Performance.

Wil je hier meer over weten? Richard Lander (Principal Program Manager of .NET Core) heeft een artikel geschreven over desktop applicaties in .NET Core 3.0.

P.S. Windows Forms en WPF zijn nu open-source!


Local dotnet tools

Sinds .NET Core 2.1 is het al mogelijk om extra tools voor dotnet te installeren op je computer. Nu is het ook mogelijk om tools per project te installeren. Hiervoor is een nieuw bestand geïntroduceerd, dat je waarschijnlijk vaak tegen zult komen in .NET Core 3.0 projecten: dotnet-tools.json. In dit bestand kun je aangeven welke tools en welke versies gebruikt worden voor het project. Om de tools uit te voeren, gebruikt je: dotnet tool run , wat erg eenvoudig op te nemen is in automatische build scripts.

Door dotnet-tools.json te gebruiken, wordt een hoop frustratie bespaard bij het draaien van een project op verschillende computers. Het nadeel: tools kunnen specifieke versies van .NET Core runtime vereisen, die je alsnog los moet installeren.


Executables and dependencies at build

Bij het builden van een .NET Core 3.0 applicatie, wordt nu ook een executable van je applicatie gemaakt. In vorige versies, gebeurde dit alleen voor self-contained applications. Een executable in de build output is vooral handig bij het distribueren, want steeds dotnet app.dll aanroepen, is niet zo praktisch.

Daarnaast worden nu ook dependencies (NuGet packages) naar de build output gekopieerd. Daardoor kun je nu eenvoudig de build map kopiëren naar een andere machine om daar te testen in een andere omgeving.


Hardware communicatie: Serial, GPIO, PWM, SPI and I2C

Internet of Things (IoT) wordt steeds populairder. Microsoft heeft goed door, dat .NET Core hierin veel kan betekenen als cross-platform platform. Goede communicatie met hardware componenten is hierbij echter essentieel. Daarom zijn er nieuwe API’s gebouwd voor GPIO, PWM, SPI en I2C, maar is ook ondersteuning voor seriële poorten in Linux toegevoegd.

Ook goed om te weten: ARM64 voor Linux wordt nu ondersteund, zodat 64-bit applicaties op een Raspberry Pi 3 gedraaid kunnen worden.


Range and Index

De hierboven genoemde features zijn behoorlijk indrukwekkend, maar als je geen desktop applicaties bouwt, niet met IoT werkt, en je niet bezig houdt met deployment, lijkt er misschien niet direct een reden om te upgraden. Stop niet met lezen, want de volgende C# 8 feature is interessant voor iedereen! Met de nieuwe Range feature is het eenvoudig om een deel van een Array te selecteren:

int[] a = { 10, 20, 30, 40, 50 };
return a[0..3]; // [10, 20, 30]

 

Behalve de Range, is er ook een nieuwe Index feature die het mogelijk maakt om een index in een range te definiëren:

int[] a = { 10, 20, 30, 40, 50 };
Index i1 = 0; // 0 from the beginning: 10
Index i2 = ^2; // 2 from the end: 40 
return a[i1..i2]; // [10, 20, 30]

Async streams

Nog meer geweldig nieuws over .NET Core, is de introductie van async streams. Async streams maken het mogelijk om resultaten van tasks af te wachten, terwijl de eerste antwoorden al verwerkt worden.

async IAsyncEnumerable<string> GetTaxReportsAsync()
{
    foreach(var request in GetTaxReportRequests())
    {
    	var result = await GetTaxReportAsync(request);
    	if (result.Success)
            yield return result.TaxReport;
    }
}

In het voorbeeld hierboven wordt een batch rapporten gegenereerd op basis van een lijst met requests. Elk rapport dat gegenereerd is, wordt alvast terug gegeven aan de gebruiker.


JSON

Tot nu toe was Json.NET de meest populaire JSON libary voor .NET. Deze library is echter gebaseerd op UTF16, wat niet altijd wenselijk is. Daarom heeft .NET Core 3.0 een Utf8JsonReader en Utf8JsonWriter meegebracht. Microsoft belooft hiermee zelfs een 100% verbetering qua performance.

Een andere manier om JSON bestanden te parsen, is door gebruik te maken van de nieuwe JsonDocument class, welke gebouwd is op de nieuwe UTF8 JSON library. Deze parser werkt vergelijkbaar met XmlDocument:

using (JsonDocument doc = JsonDocument.Parse(json))
{
    JsonElement root = doc.RootElement;
    JsonElement person = root[1];
    string firstName = person[0].GetString();
}

Unload assemblies

Middels AssemblyLoadContext.LoadFromAssemblyPath en AssemblyLoadContext.Unload kunnen assemblies eenvoudig geload en ge-unload worden.


MetadataLoadContext

De nieuwe MetadataLoadContext heeft veel weg van het oude vertrouwde assembly loading, maar er is een groot verschil! Voorheen was het alleen mogelijk om de inhoud van een .dll bestand te analyseren door deze eerst volledig in te laden als assembly en vervolgens alle types te doorlopen. Met .NET Core 3.0 heeft Microsoft ervoor gezorgd dat alleen de metadata geladen hoeft te worden, zonder dat alle classes gelijk aan het AppDomain worden toegevoegd.

var paths = new string[] {@"plugin.a.dll", @"plugin.b.dll"};
var resolver = new PathAssemblyResolver(paths);
var pluginInterface = typeof(IPlugin);
using (var context = new MetadataLoadContext(resolver))
{
    var assembly = context.LoadFromAssemblyName("plugin.a");
    foreach (var type in assembly.GetTypes())
    {
        if (type.IsClass && pluginInterface.IsAssignableFrom(type))
            Console.WriteLine($"Plugin found: {t.FullName}");
    }
}

SequenceReader

In .NET Core 3.0 is System.Buffers.SequenceReader toegevoegd, om ReadOnlySequence objecten te kunnen lezen. Op dit moment zijn er nog geen echte voorbeelden beschikbaar voor het gebruik van de SequenceReader, waardoor het een beetje onduidelijk is waarvoor deze feature gebruikt kan worden, maar het is wellicht interessant om een stream van bytes uit een camera of barcode scanner te verwerken.

public static void ReadLines(ReadOnlySequence<byte> sequence)
{
    var reader = new SequenceReader<byte>(sequence);

    while (!reader.End)
    {
       reader.Read();
    }
}

Standaard implementatie van interfaces

C# heeft al sinds de eerste versie ondersteuning voor interfaces en abstract classes. In C# 8 heeft Microsoft deze gecombineerd tot een nieuwe feature! Het is mogelijk om een standaard implementatie toe te voegen aan een methode van een interface. Het ziet er heel raar uit, maar het volgende voorbeeld is correct:

interface IBook
{
    public void Print()
    {
        Console.WriteLine("This book has no content.");
    }
}

Dus we hebben eigenlijk helemaal geen abstracte classes meer nodig? Misschien, maar wees voorzichtig met deze nieuwe feature, want het is heel makkelijk te misbruiken om geen aparte service classes meer te hoeven bouwen. Het is bijvoorbeeld veel beter om een BookPrinter class te maken met een Print(IBook book) methode, dan bestaande classes uit te breiden met een interface die vergelijkbare logica bevat.


De ontwikkeling en release van .NET Core 3.0 loopt parallel met die van ASP.NET Core en Entity Framework Core. Daarnaast is .NET Core 3.0 nauw verbonden met .NET Standard, C# 8 and F# 4.6. En last but not least, zijn er ook nieuwe Docker containers beschikbaar voor elke preview release.


 

 

 

Meer informatie

 

 

 

https://docs.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-3-0
https://github.com/dotnet/core/tree/master/release-notes/3.0
https://github.com/dotnet/core/blob/master/roadmap.md
https://www.infoq.com/articles/default-interface-methods-cs8

 

 

 

Dit artikel is als eerste verschenen op 28 maart 2019 op blog.vincentbitter.nl waarna deze door Vincent Bitter vertaald is voor Team Rockstars IT.