Zum Inhalt springen

C# CSharp Programmierung fortgeschrittene Techniken – Von Variablen zu Azure Cloud Techniken.

C# Charp Programmierung Tutorial

Werbung: Wenn Du ein gutes C# Lern-Buch benötigst, können wir Dir folgendes Buch von Amazon.de empfehlen:

Inhaltsverzeichnis

41. CQRS und Event Sourcing in C#

CQRS (Command Query Responsibility Segregation) und Event Sourcing sind fortgeschrittene Architekturansätze, die oft in skalierbaren Systemen verwendet werden. Sie ermöglichen es, Lese- und Schreiboperationen zu trennen und alle Zustandsänderungen als Ereignisse zu speichern.

  • CQRS: Trennung der Befehle (zum Ändern des Zustands) von den Abfragen (zum Lesen des Zustands).
  • Event Sourcing: Jede Zustandsänderung wird als Ereignis gespeichert, und der aktuelle Zustand des Systems kann durch Wiederholen dieser Ereignisse rekonstruiert werden.

C# CSharp Beispiel für CQRS

Ein einfaches CQRS-Modell in C#:

 public interface ICommand { }
public interface IQuery<TResult> { }

public class CreateUserCommand : ICommand
{
public string Name { get; set; }
}

public class GetUserByIdQuery : IQuery<User>
{
public int UserId { get; set; }
}

// Handler für Befehle
public class CreateUserHandler
{
public void Handle(CreateUserCommand command)
{
// Logik zum Erstellen des Benutzers
}
}

// Handler für Abfragen
public class GetUserByIdHandler
{
public User Handle(GetUserByIdQuery query)
{
// Logik zum Abrufen des Benutzers
return new User { Id = query.UserId, Name = "Max" };
}
}

In einer echten CQRS-Anwendung würdest du für jede Art von Befehlen und Abfragen separate Handler haben, die den Zugriff auf die Datenbank oder den Nachrichtenspeicher steuern.

42. Fortgeschrittene Optimierungen mit Span<T>, Memory<T> und ArrayPool<T>

Neben den bereits besprochenen Speicheroptimierungen kannst du auch auf den ArrayPool<T> zurückgreifen, um wiederverwendbare Arrays zu nutzen und die Performance bei speicherintensiven Operationen zu steigern.

Beispiel für die Verwendung von ArrayPool<T>:

 using System.Buffers;

var pool = ArrayPool<int>.Shared;
int[] array = pool.Rent(1000); // Mietet ein Array aus dem Pool

try
{
// Verarbeitung des Arrays
}
finally
{
pool.Return(array); // Gibt das Array zurück in den Pool
}

Mit ArrayPool kannst du vermeiden, dass Arrays häufig alloziert und freigegeben werden, was den Garbage Collector entlastet und die Performance verbessert.

43. Middleware in ASP.NET Core

Middleware ist ein wichtiges Konzept in ASP.NET Core. Es handelt sich um eine Pipeline von Komponenten, durch die jede HTTP-Anfrage geleitet wird, bevor eine Antwort zurückgegeben wird. Jede Middleware-Komponente kann die Anfrage verarbeiten oder an die nächste Middleware weiterleiten.

Beispiel für eigene Middleware:

 public class MeineMiddleware
{
private readonly RequestDelegate _next;

public MeineMiddleware(RequestDelegate next)
{
_next = next;
}

public async Task InvokeAsync(HttpContext context)
{
// Vor der nächsten Middleware oder dem Controller ausführen
Console.WriteLine("Vor dem Controller");

await _next(context); // Nächste Middleware oder Controller aufrufen

// Nach der nächsten Middleware oder dem Controller ausführen
Console.WriteLine("Nach dem Controller");
}
}

// Registrierung der Middleware in der Pipeline
public void Configure(IApplicationBuilder app)
{
app.UseMiddleware<MeineMiddleware>();
}

In diesem Beispiel wird eine eigene Middleware erstellt, die vor und nach der Verarbeitung durch den Controller ausgeführt wird. Middleware kann verwendet werden, um Authentifizierung, Logging, Fehlerbehandlung und andere querliegende Aspekte der Anwendung zu implementieren.

44. Fortgeschrittene Parallelität mit Parallel.ForEach und PLINQ

Wenn du sehr große Datenmengen parallel verarbeiten möchtest, bietet C# mehrere fortgeschrittene Techniken wie Parallel.ForEach und PLINQ (Parallel LINQ), die dir helfen können, die Rechenzeit zu reduzieren, indem sie Aufgaben auf mehrere Prozessoren verteilen.

Parallel.ForEach

 var daten = Enumerable.Range(1, 1000).ToList();

Parallel.ForEach(daten, zahl =>
{
Console.WriteLine($"Verarbeite Zahl: {zahl} von Thread {Thread.CurrentThread.ManagedThreadId}");
});

In diesem Beispiel wird die Liste der Zahlen parallel verarbeitet, wobei jeder Eintrag in einem separaten Thread bearbeitet werden kann.

PLINQ (Parallel LINQ)

PLINQ ist eine Erweiterung von LINQ, die Daten parallel abfragt. Du kannst die parallele Verarbeitung einfach aktivieren, indem du die Methode AsParallel() verwendest.

csharpCode kopierenvar zahlen = Enumerable.Range(1, 1000);

var geradeZahlen = zahlen.AsParallel()
                         .Where(n => n % 2 == 0)
                         .ToList();

foreach (var zahl in geradeZahlen)
{
    Console.WriteLine(zahl);
}

PLINQ eignet sich hervorragend für CPU-intensive Aufgaben, da es die Abfragen automatisch parallelisiert und somit auf mehreren Threads ausgeführt.

45. Immutable Collections und Thread-Sicherheit

Immutable Collections sind Sammlungen, die nach ihrer Erstellung nicht mehr geändert werden können. Dies macht sie besonders nützlich in Multithreading-Szenarien, da sie sicher zwischen Threads verwendet werden können, ohne dass Synchronisationsprobleme auftreten.

Beispiel für eine immutable Liste:

 using System.Collections.Immutable;

ImmutableList<int> meineListe = ImmutableList.Create(1, 2, 3);

// Füge ein Element hinzu, was eine neue Liste zurückgibt
ImmutableList<int> neueListe = meineListe.Add(4);

Console.WriteLine("Alte Liste: " + string.Join(", ", meineListe)); // Ausgabe: 1, 2, 3
Console.WriteLine("Neue Liste: " + string.Join(", ", neueListe)); // Ausgabe: 1, 2, 3, 4

Immutable Collections sind sehr nützlich, wenn du sicherstellen möchtest, dass Daten nicht versehentlich verändert werden können, insbesondere in Anwendungen, die viele parallele Zugriffe auf dieselben Daten haben.

46. Fortgeschrittene Fehlerbehandlung mit Polly

Polly ist eine leistungsstarke .NET-Bibliothek zur Implementierung von Resilienzstrategien wie Retry, Circuit Breaker, Timeout und mehr. Sie wird oft in Microservices verwendet, um die Fehlertoleranz zu verbessern.

Beispiel für einen Retry-Mechanismus mit Polly:

 using Polly;
using System;

var policy = Policy.Handle<Exception>().Retry(3, (exception, retryCount) =>
{
Console.WriteLine($"Fehler aufgetreten. Versuche erneut... ({retryCount})");
});

policy.Execute(() =>
{
// Simuliere einen Fehler
Console.WriteLine("Versuche, eine gefährliche Aktion auszuführen...");
throw new Exception("Fehler");
});

In diesem Beispiel wird bei Auftreten einer Ausnahme die Aktion automatisch bis zu dreimal wiederholt. Polly bietet darüber hinaus Circuit Breaker, Fallbacks und viele weitere Resilienzstrategien, die besonders nützlich sind, wenn du mit Netzwerkanfragen oder Datenbankoperationen arbeitest, bei denen Fehler erwartet werden.

47. SignalR – Echtzeit-Kommunikation

SignalR ist eine Bibliothek in ASP.NET Core, die dir die Möglichkeit gibt, Echtzeit-Funktionalitäten in deine Anwendungen zu integrieren. Dies ist besonders nützlich für Web-Apps, die sofortige Updates erfordern, wie z.B. Chat-Anwendungen, Live-Dashboards oder Multiplayer-Spiele.

Einfacher SignalR-Server:

 using Microsoft.AspNetCore.SignalR;

public class ChatHub : Hub
{
public async Task SendeNachricht(string benutzer, string nachricht)
{
await Clients.All.SendAsync("EmpfangeNachricht", benutzer, nachricht);
}
}

// In der Startup-Datei
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
}

public void Configure(IApplicationBuilder app)
{
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<ChatHub>("/chatHub");
});
}

Einfacher SignalR-Client (JavaScript):

 const connection = new signalR.HubConnectionBuilder()
.withUrl("/chatHub")
.build();

connection.on("EmpfangeNachricht", (benutzer, nachricht) => {
console.log(benutzer + ": " + nachricht);
});

await connection.start();
await connection.invoke("SendeNachricht", "Max", "Hallo, Welt!");

SignalR verwendet WebSockets, um eine bidirektionale Echtzeit-Kommunikation zwischen Server und Client zu ermöglichen. Wenn WebSockets nicht verfügbar sind, verwendet SignalR andere Transportmechanismen wie Server-Sent Events oder Long Polling.

48. .NET MAUI für plattformübergreifende Apps

.NET MAUI (Multi-platform App UI) ist die nächste Generation von Xamarin.Forms und ermöglicht es dir, plattformübergreifende Anwendungen für Android, iOS, macOS und Windows mit einer einzigen C#-Codebasis zu erstellen.

Beispiel für eine einfache .NET MAUI-App:
csharpCode kopierenusing Microsoft.Maui.Controls;

public class MainPage : ContentPage
{
    public MainPage()
    {
        var button = new Button
        {
            Text = "Klicke mich",
            VerticalOptions = LayoutOptions.Center,
            HorizontalOptions = LayoutOptions.Center
        };

        button.Clicked += (sender, args) =>
        {
            button.Text = "Du hast mich geklickt!";
        };

        Content = new StackLayout
        {
            Children = { button }
        };
    }
}

Mit .NET MAUI kannst du eine Benutzeroberfläche erstellen, die auf allen Plattformen einheitlich aussieht und funktioniert. Es wird auch eine tiefe Integration mit nativen Funktionen jeder Plattform geboten.

49. Minimal APIs in .NET 6+

Mit Minimal APIs in .NET 6 kannst du schnell und einfach Web-APIs erstellen, ohne die umfangreiche Struktur von MVC oder Razor Pages zu benötigen.

Beispiel für eine Minimal API:

 var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/", () => "Hallo, Minimal API!");
app.MapPost("/benutzer", (Benutzer benutzer) => $"Willkommen {benutzer.Name}!");

app.Run();

public class Benutzer
{
public string Name { get; set; }
}

Minimal APIs bieten eine einfache und schnelle Möglichkeit, API-Endpunkte mit wenig Boilerplate-Code zu erstellen. Sie sind ideal für kleine Microservices oder schnell prototypisierte Anwendungen.

50. MediatR – Implementierung von CQRS

MediatR ist ein beliebtes .NET-Bibliothekspaket, das die Implementierung des CQRS-Musters erleichtert. Es ermöglicht dir, Befehle und Abfragen zu kapseln und sorgt für eine lose Kopplung zwischen deinen Anwendungsschichten.

Beispiel für die Verwendung von MediatR:

 using MediatR;

// Definiere einen Befehl
public class ErstelleBenutzerCommand : IRequest<int>
{
public string Name { get; set; }
}

// Handler für den Befehl
public class ErstelleBenutzerHandler : IRequestHandler<ErstelleBenutzerCommand, int>
{
public Task<int> Handle(ErstelleBenutzerCommand request, CancellationToken cancellationToken)
{
// Logik zur Erstellung des Benutzers
return Task.FromResult(1); // Beispiel: Benutzer-ID zurückgeben
}
}

// In der Startup-Datei
public void ConfigureServices(IServiceCollection services)
{
services.AddM

50. MediatR – Implementierung von CQRS (Fortsetzung)

MediatR vereinfacht das CQRS-Muster durch das Senden von Befehlen (Commands) und Abfragen (Queries) über eine zentrale Instanz, den Mediator. Es sorgt für eine lose Kopplung der verschiedenen Schichten einer Anwendung, indem es den direkten Aufruf von Services durch eine zentrale Vermittlungsstelle ersetzt.

Hier geht’s weiter mit der Registrierung des MediatR-Systems und einer vollständigen Implementierung:

Registrierung in der Startup.cs oder Program.cs Datei:
 public void ConfigureServices(IServiceCollection services)
{
services.AddMediatR(typeof(ErstelleBenutzerHandler).Assembly); // Registrierung aller Handler im angegebenen Assembly
}
Nutzung des MediatR-Mediators in einem Controller oder Service:
 public class BenutzerController : ControllerBase
{
private readonly IMediator _mediator;

public BenutzerController(IMediator mediator)
{
_mediator = mediator;
}

[HttpPost("/benutzer")]
public async Task<IActionResult> ErstelleBenutzer(ErstelleBenutzerCommand command)
{
var erstellteBenutzerId = await _mediator.Send(command); // Befehl an den Mediator senden
return Ok(erstellteBenutzerId);
}
}

In diesem Beispiel sehen wir, wie eine Anfrage über den Mediator an den richtigen Handler delegiert wird, ohne dass der Controller direkt wissen muss, wie der Benutzer erstellt wird. Dies sorgt für eine klare Trennung der Verantwortlichkeiten und verbessert die Testbarkeit und Wartbarkeit der Anwendung.

Seiten: 1 2 3 4 5 6