Erweiterte API-Resilienz mit Refit, Polly, Refitter, Rate Limiting und Circuit Breaker

Nachdem wir die grundlegende Integration von Refit, Polly und Refitter in API-Projekte besprochen haben, wollen wir nun einen Schritt weiter gehen und uns mit fortgeschrittenen Resilienzmechanismen befassen. Besonders im Kontext von APIs, die häufige Anfragen stellen, ist es wichtig, sicherzustellen, dass die Anwendung Anfrageraten kontrolliert und bei Erreichen von Grenzen angemessen reagiert. Hier kommen das Rate Limiting, die AsyncRateLimitPolicy und der Circuit Breaker ins Spiel.

1. Rate Limiting: Anfragen pro Sekunde beschränken

Rate Limiting ist eine wichtige Strategie, um sicherzustellen, dass eine Anwendung API-Server nicht überlastet. Eine gängige Anforderung ist es, die Anzahl der API-Anfragen auf einen bestimmten Wert pro Sekunde zu begrenzen.

Polly bietet hierfür die AsyncRateLimitPolicy, mit der Sie die Anzahl der Anfragen pro Zeiteinheit begrenzen können. Dies ist besonders nützlich, wenn die API, die Sie konsumieren, eigene Ratenlimits durchsetzt.

Beispiel:

var rateLimitPolicy = Policy.RateLimitAsync(60, TimeSpan.FromSeconds(1));

services.AddRefitClient<IMyApi>()
    .ConfigureHttpClient(c => c.BaseAddress = new Uri("https://api.example.com"))
    .AddPolicyHandler(rateLimitPolicy)
    .AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600)));

In diesem Beispiel erlaubt das RateLimitPolicy, dass maximal 60 Anfragen pro Sekunde gestellt werden. Wenn dieses Limit überschritten wird, wird eine RateLimitRejectedException ausgelöst, die entweder behandelt oder verzögert werden kann.

2. Circuit Breaker: Verhindern von Überlastungen

Der Circuit Breaker ist ein weiterer Resilienzmechanismus, der dazu dient, eine API vor Überlastungen zu schützen, indem er fehlerhafte Anfragen frühzeitig unterbricht. Der Circuit Breaker wird aktiviert, wenn eine bestimmte Anzahl von Fehlern innerhalb eines bestimmten Zeitraums auftritt, und verhindert weitere Anfragen, bis die API sich wieder stabilisiert hat.

Beispiel mit Circuit Breaker:

var circuitBreakerPolicy = Policy.Handle<HttpRequestException>()
    .CircuitBreakerAsync(2, TimeSpan.FromMinutes(1));

services.AddRefitClient<IMyApi>()
    .ConfigureHttpClient(c => c.BaseAddress = new Uri("https://api.example.com"))
    .AddPolicyHandler(rateLimitPolicy)
    .AddPolicyHandler(circuitBreakerPolicy)
    .AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600)));

In diesem Beispiel wird der Circuit Breaker nach zwei aufeinanderfolgenden Fehlern aktiviert und blockiert weitere Anfragen für eine Minute. Dies gibt der API Zeit, sich zu erholen, und verhindert, dass eine fehlerhafte API weiter überlastet wird.

3. Kombination von Rate Limiting und Circuit Breaker

Die Kombination aus Rate Limiting und Circuit Breaker sorgt für eine robuste API-Integration, die sowohl gegen Überlastung als auch gegen Ausfälle geschützt ist. Durch das Einrichten von Ratenlimits wird sichergestellt, dass API-Server nicht durch zu viele Anfragen überlastet werden. Gleichzeitig schützt der Circuit Breaker die Anwendung vor wiederholten Fehlern, indem er nach einem bestimmten Schwellenwert eingreift.

Erweitertes Beispiel:

public void ConfigureServices(IServiceCollection services)
{
    var rateLimitPolicy = Policy.RateLimitAsync(60, TimeSpan.FromSeconds(1));
    var circuitBreakerPolicy = Policy.Handle<HttpRequestException>()
        .CircuitBreakerAsync(2, TimeSpan.FromMinutes(1));
    
    services.AddRefitClient<IMyApi>()
        .ConfigureHttpClient(c => c.BaseAddress = new Uri("https://api.example.com"))
        .AddPolicyHandler(rateLimitPolicy)
        .AddPolicyHandler(circuitBreakerPolicy)
        .AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(10)))
        .AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600)));
}

In diesem erweiterten Beispiel werden alle drei Mechanismen kombiniert, um eine API-Integration zu schaffen, die nicht nur effizient, sondern auch äußerst widerstandsfähig ist. Diese Konfiguration ist besonders nützlich in Produktionsumgebungen, in denen hohe Stabilität und Zuverlässigkeit erforderlich sind.

4. Fazit

Die Implementierung von Rate Limiting und Circuit Breaker in Kombination mit Refit, Polly und Refitter bietet eine umfassende Lösung für die API-Integration in .NET-Projekten. Diese Tools sorgen dafür, dass Ihre Anwendung Anfragen effektiv verwaltet, API-Server vor Überlastung schützt und dennoch flexibel und robust genug ist, um auch unter schwierigen Bedingungen stabil zu bleiben.

Durch den Einsatz dieser fortgeschrittenen Resilienzstrategien können Sie sicherstellen, dass Ihre Anwendung nicht nur effizient, sondern auch nachhaltig und skalierbar ist.

Effiziente API-Integration mit Refit, Polly und Refitter: Eine umfassende Betrachtung

In der modernen Softwareentwicklung spielt die Integration externer APIs eine zentrale Rolle. Die Kommunikation mit diesen APIs sollte nicht nur effizient, sondern auch robust und einfach zu handhaben sein. Drei wichtige Tools, die diesen Prozess in .NET-Projekten erheblich vereinfachen, sind Refit, Polly und Refitter. In diesem Artikel betrachten wir, wie diese Tools zusammenarbeiten und wie sie die Entwicklung von API-Clients optimieren.

1. Refit: Einfacher API-Zugriff durch deklarative Interfaces

Refit ist eine beliebte Bibliothek in der .NET-Welt, die es Entwicklern ermöglicht, RESTful APIs über deklarative Interfaces anzusprechen. Anstatt für jeden API-Aufruf manuell HttpClient-Code zu schreiben, definieren Sie einfach ein Interface, das die Endpunkte der API beschreibt. Refit generiert dann automatisch den entsprechenden HTTP-Client.

public interface IMyApi
{
    [Get("/users/{id}")]
    Task<User> GetUserAsync(int id);

    [Post("/users")]
    Task<User> CreateUserAsync([Body] User user);
}

Mit Refit ist es so einfach wie:

var apiClient = RestService.For<IMyApi>("https://api.example.com");
var user = await apiClient.GetUserAsync(1, Cancellationtoken.None);

Diese Einfachheit führt zu einer klareren und leichter wartbaren Codebasis, insbesondere wenn Ihre Anwendung mit zahlreichen APIs interagiert.

2. Polly: Resilienz für API-Aufrufe

Polly ist eine leistungsstarke .NET-Bibliothek, die es ermöglicht, Resilienzstrategien wie Retry, Circuit Breaker und Timeout in Ihre API-Aufrufe zu integrieren. Dies ist besonders wichtig in Szenarien, in denen Netzwerkanfragen fehlschlagen oder unvorhersehbare Latenzen auftreten können.

Beispiel mit Polly:

services.AddHttpClient<IMyApi, MyApiClient>()
    .AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600)));

Hier wird Polly so konfiguriert, dass bei vorübergehenden Fehlern bis zu drei Wiederholungsversuche unternommen werden. Dies erhöht die Robustheit Ihrer Anwendung und minimiert Ausfallzeiten aufgrund von temporären Netzwerkproblemen.

3. Refitter: Automatische Generierung von Refit-Interfaces

Refitter ist ein NuGet-Paket, das speziell für die automatische Generierung von Refit-Interfaces aus OpenAPI-Definitionen entwickelt wurde. Dies spart nicht nur Zeit, sondern stellt auch sicher, dass Ihre API-Interfaces immer synchron mit der API-Dokumentation bleiben.

Beispiel für die Verwendung von Refitter:

dotnet refitter generate --openapi https://api.example.com/swagger.json --namespace MyProject.ApiClients --output ./GeneratedApi

Dieser Befehl generiert C#-Interfaces basierend auf der OpenAPI-Definition. Diese Interfaces können dann direkt in Ihrem Projekt verwendet werden, um API-Aufrufe zu tätigen, ohne dass manuelle Anpassungen erforderlich sind.

4. Zusammenspiel von Refit, Polly und Refitter

Die Kombination dieser drei Tools bietet eine flexible, skalierbare und robuste Lösung für API-Aufrufe in .NET-Projekten. Während Refit die Interaktion mit APIs vereinfacht, sorgt Polly dafür, dass diese Interaktionen auch in schwierigen Netzwerksituationen zuverlässig bleiben. Refitter fügt einen weiteren Automatisierungsgrad hinzu, indem es sicherstellt, dass die API-Interfaces stets aktuell und korrekt sind.

Komplettes Beispiel:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRefitClient<IMyApi>()
        .ConfigureHttpClient(c => c.BaseAddress = new Uri("https://api.example.com"))
        .AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(10)))
        .AddTransientHttpErrorPolicy(policy => policy.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(600)));
}

In diesem Beispiel arbeiten alle drei Tools nahtlos zusammen, um eine API-Integration zu ermöglichen, die sowohl einfach zu implementieren als auch robust gegenüber Ausfällen ist.

5. Fazit

Die Verwendung von Refit, Polly und Refitter in Kombination ermöglicht es Entwicklern, API-Clients schnell, effizient und fehlerfrei zu erstellen. Refit vereinfacht die API-Integration, Polly fügt wichtige Resilienzmechanismen hinzu, und Refitter automatisiert die Generierung von API-Interfaces aus OpenAPI-Definitionen. Zusammen bieten diese Tools eine umfassende Lösung, die sowohl die Entwicklungszeit verkürzt als auch die Zuverlässigkeit der Anwendung erhöht.

Für jedes .NET-Projekt, das regelmäßig mit externen APIs interagiert, sind diese Tools nahezu unverzichtbar und tragen erheblich zur Stabilität und Wartbarkeit der Codebasis bei.

Die Zukunft der IT-Beratung: Trends, die Sie im Auge behalten sollten

In der dynamischen Welt der IT-Beratung ist es entscheidend, stets am Puls der Zeit zu bleiben. Die rasante technologische Entwicklung bringt nicht nur Herausforderungen, sondern auch zahlreiche Chancen mit sich. In diesem Beitrag werfen wir einen Blick auf die wichtigsten Trends, die die IT-Beratung in den kommenden Jahren prägen werden.

1. Künstliche Intelligenz und Automatisierung

Künstliche Intelligenz (KI) und Automatisierung sind längst keine Zukunftsmusik mehr. Sie revolutionieren, wie Unternehmen arbeiten und Entscheidungen treffen. Für IT-Berater bedeutet dies, dass sie ihren Kunden dabei helfen müssen, diese Technologien effektiv zu integrieren, um Wettbewerbsvorteile zu erzielen.

2. Cloud-Computing und hybride Umgebungen

Die Cloud bleibt ein zentrales Element der IT-Infrastruktur. Doch nicht nur die Public Cloud steht im Fokus, sondern auch hybride Lösungen, die die Vorteile der Cloud mit On-Premise-Infrastrukturen kombinieren. IT-Berater müssen ihre Kunden dabei unterstützen, die richtige Balance zu finden und maßgeschneiderte Cloud-Strategien zu entwickeln.

3. Cybersicherheit als Top-Priorität

Mit der zunehmenden Vernetzung steigt auch das Risiko von Cyberangriffen. IT-Berater müssen ihre Kunden dabei unterstützen, robuste Sicherheitsmaßnahmen zu implementieren und sich proaktiv gegen Bedrohungen zu schützen. Dies erfordert ein tiefes Verständnis der neuesten Sicherheitslösungen und -strategien.

4. Datenanalyse und Big Data

Daten sind das neue Gold. Die Fähigkeit, große Datenmengen zu analysieren und daraus verwertbare Erkenntnisse zu gewinnen, ist für Unternehmen von unschätzbarem Wert. IT-Berater müssen ihren Kunden helfen, effektive Datenstrategien zu entwickeln, um diese wertvollen Ressourcen optimal zu nutzen.

5. Nachhaltigkeit und Green IT

Nachhaltigkeit wird in der IT-Welt immer wichtiger. Green IT, also umweltfreundliche Technologien und Prozesse, gewinnt an Bedeutung. IT-Berater sollten ihre Kunden dabei unterstützen, nachhaltige IT-Strategien zu entwickeln, die nicht nur die Umwelt schonen, sondern auch langfristige Kosteneinsparungen ermöglichen.

Fazit

Die IT-Beratung steht vor spannenden Zeiten. Die genannten Trends bieten zahlreiche Möglichkeiten, die Geschäftswelt von morgen aktiv mitzugestalten. Bei Minicon sind wir bereit, unsere Kunden auf diesem Weg zu begleiten und ihnen zu helfen, diese Chancen zu nutzen. Gemeinsam gestalten wir die digitale Zukunft.

Nuget packages .Net Core 3.1

Fragen die in diesen Artikel beantwortet werden:

  • Wie kann ich automatisch (on build) nuget-Packages erstellen?
  • Wie kann ich Parameter an den nuget build Task übergeben?
  • Wie kann ich code duplizierung vermeiden?
  • Wie kann ich weitere Dateien in mein nuget packages einfügen?
  • Was muss ich tun um SourceLink in den nuget packages zu aktivieren?

Visual Studio 2019 hat für die Erstellung der NuGet Packages eine eingebaute Möglichkeit NuGet-Pakete zu erstellen. Die Möglichkeit wurde nicht mit den ersten Versionen des Visual Studios  bereitgestellt und ist zum aktuellen Zeitpunkt (anfang 2021) nicht voll umfänglich verfübar. Es gibt keine Möglichkeit, je nach Configuration (Debug/Release) unterschiedliche packages oder dependencies hinzuzufügen. Ebenso können keine Build-Dateien und Targets hinzugefügt werden. Aus diesen Grund wird hier die realisierung mit einer „nuspec“-Datei betrachtet.

Um die wiederverwendung zu vereinfachen, wurde innerhalb der benötigten Projekte in Visual Studio ein include verwendet, welches via <Import Project=“..\Default.csproj“ /> im project hinzugefügt werden.

Hier ein Beispiel einer csproj-Datei eines Projektes:

<Project Sdk="Microsoft.NET.Sdk">
    <!-- Modify properties for project here -->
    <PropertyGroup>
        <!-- You can modify your nuget package name here. -->
        <PackageId>$(MSBuildProjectName)</PackageId>
        <!-- If not added here, is default 1.0.0 is used. -->
        <Version>1.0.2</Version>
    </PropertyGroup>
       <!-- Include default project -->
    <Import Project="..\default.csproj" />
    <ItemGroup>
        <!-- Add package references. -->
    </ItemGroup>
    <ItemGroup>
        <!-- Add project references. -->
    </ItemGroup>
</Project>

Hier der Inhalt der default.csproj

<Project DefaultTargets="Build"
    xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <!-- Change or update values in this Property group -->
    <PropertyGroup>
        <Authors></Authors>
        <Company></Company>
        <RepositoryUrl></RepositoryUrl>
        <!-- E.g. git -->
        <RepositoryType></RepositoryType>
        <Description></Description>
        <!-- If you want to publish on *every* build change this to true, consider that nuget packages needs to be unique and once published they should not be changed. This might make sense on the CI-System. -->
        <PublishRepositoryUrl>false</PublishRepositoryUrl>
    </PropertyGroup>
    <PropertyGroup>
<Deterministic>true</Deterministic>
<IncludeSymbols>true</IncludeSymbols> <SymbolPackageFormat>snupkg</SymbolPackageFormat> <EmbedUntrackedSources>true</EmbedUntrackedSources> <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild> <OutputPath>bin\$(Configuration)</OutputPath> <DocumentationFile>bin\$(Configuration)\$(MSBuildProjectName).xml</DocumentationFile> <TargetFramework>netcoreapp3.1</TargetFramework> <Nullable>enable</Nullable> <GeneratePackageOnBuild>false</GeneratePackageOnBuild> </PropertyGroup> <ItemGroup Label="NugetAndDefaults"> <PackageReference Include="Microsoft.SourceLink.AzureDevOpsServer.Git" Version="1.0.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> <!-- Add your Server variables: $(GitServerDomain) and $(GitServerPath) --> <SourceLinkAzureDevOpsServerGitHost Include="$(GitServerDomain)" VirtualDirectory="$(GitServerPath)" /> </ItemGroup> <Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Exec Command="..\Nuget\nuget.exe pack ..\Nuget\$(PackageId).nuspec -Properties Version=$(Version);Id=$(PackageId);Title=$(PackageId);ProjectName=$(MSBuildProjectName);Configuration=$(Configuration) -Output bin\$(Configuration) " /> </Target> </Project>

Nun wird beim Build des Projectes eine nuspec-Datei benötigt: $(PackageId).nuspec

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
    <metadata>
        <id>$id$</id>
        <title>$title$</title>
        <version>$version$</version>
        <!-- Add the authors -->
        <authors></authors>
        <!-- Add the owners -->
        <owners></owners>
        <requireLicenseAcceptance>false</requireLicenseAcceptance>
        <developmentDependency>false</developmentDependency>
        <!-- Add the description -->
        <description></description>
        <!-- All you required package dependencies -->
        <dependencies></dependencies>
    </metadata>
    <files>
        <file src="..\README.md" target="README.md" />
        <file src="..\$ProjectName$\bin\$configuration$\netcoreapp3.1\$ProjectName$.dll" target="lib\netcoreapp3.1\$ProjectName$.dll" />
        <file src="..\$ProjectName$\bin\$configuration$\netcoreapp3.1\$ProjectName$.pdb" target="lib\netcoreapp3.1\$ProjectName$.pdb" />
        <file src="..\$ProjectName$\bin\$configuration$\$ProjectName$.xml" target="Build\$ProjectName$.xml" />
        <file src="$id$.targets" target="Build\$id$.targets" />
    </files>
</package>

In this example, there is an additional file added for the xml documentation file, which later linked in the target project. This is done in a Build-Target within the nuget package, this file must be named $(PackageId).targets:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <ItemGroup>
        <!-- Replace Contoso.xml with the documentation file needed. -->
        <None Include="$(MSBuildThisFileDirectory)\Contoso.xml">
            <Link>Contoso.xml</Link>            <CopyToOutputDirectory>Always</CopyToOutputDirectory>
        </None>
    </ItemGroup>
</Project>

Folgende inhalte folgen hier noch:

  • git links
  • t4 um das  nuspec file zu erstellen.
  • Lösung als nuget package
  • Eigene GUI um packages zu erzeugen

Minicon wird zur Minicon eG

Mit der Gründung am 18.05.2020 und der finalen Eintragung ins Handelsregister ist Minicon nun eine eingetragene Genossenschaft (eG).

Die Gründungsmitglieder sind:

  • Daniel Ivanovic
  • Andrey Mir
  • Michael Nikolaus (Vorstand)