HttpClient og Refit i .NET MAUI: Type-Safe REST API Integration (2026)
Sådan opsætter du type-safe REST API-integration i .NET MAUI med IHttpClientFactory, Refit og Polly. Fra MauiProgram til authenticated calls, med produktionsklare kodeeksempler jeg selv har shippet.
Type-safe REST API-integration i .NET MAUI opnås bedst ved at kombinere IHttpClientFactory til livscyklus-styring, Refit til deklarative klient-interfaces og Polly til retry og circuit breaker. Kombinationen fjerner boilerplate, isolerer HTTP-detaljer bag et interface og gør din netværkskode testbar. I denne guide viser jeg dig hele opsætningen fra MauiProgram.cs til authenticated calls, med kode jeg selv har shippet i tre produktions-apps.
Brug IHttpClientFactory fra Microsoft.Extensions.Http, aldrig new HttpClient() direkte i view models.
Refit genererer type-safe klient-implementeringer fra et interface, hvilket eliminerer manuel JSON- og URL-håndtering.
Polly tilføjer retry, timeout og circuit breaker via Microsoft.Extensions.Http.Resilience uden at ændre din API-kode.
DelegatingHandlers er det rigtige sted at tilføje Bearer-tokens, logging og korrelations-ID'er (ikke i hver enkelt kald).
iOS kræver eksplicit NSAppTransportSecurity-konfiguration for lokale HTTP-endpoints under udvikling.
Kombinér IConnectivity med en outbox-tabel i SQLite for at understøtte kortvarige netværksafbrydelser.
Hvorfor du aldrig bør bruge new HttpClient() i MAUI
Det klassiske fejltrin i mobile .NET-apps er at instantiere new HttpClient() pr. kald. Klassen implementerer IDisposable, så udviklere pakker det pænt i using, og udmatter derefter socket-poolen efter få tusinde forespørgsler. På Android manifesterer det sig som SocketException under load. På iOS ses det som mystiske timeouts. Jeg fangede selv den her bug i en produktions-app, hvor QA aldrig så den, fordi den kun optrådte efter 30+ minutters brug. Ikke sjovt at debugge fra release notes.
IHttpClientFactory løser tre problemer på én gang: den genbruger HttpMessageHandler-instanser (som er de dyre objekter), den roterer handlers hvert andet minut for at respektere DNS-ændringer, og den lader dig konfigurere navngivne eller typede klienter centralt. I .NET MAUI er factory tilgængelig via Microsoft.Extensions.Http-pakken og integrerer direkte med den indbyggede DI-container. Se Microsofts officielle vejledning om IHttpClientFactory for baggrund.
En anden fordel: factory'en samarbejder med Polly, så retry- og circuit-breaker-politikker anvendes automatisk på hver forespørgsel, uden at forurene din forretningslogik. Vi kobler det sammen i næste sektion.
Opsætning af IHttpClientFactory i MauiProgram
Så, lad os starte med at tilføje pakkerne. I .NET 9 og nyere er Microsoft.Extensions.Http allerede med som transitiv afhængighed, men du skal eksplicit tilføje resilience- og Refit-pakkerne:
Konfigurér derefter en navngiven klient i MauiProgram.cs. Personligt foretrækker jeg navngivne klienter over typede, fordi de er nemmere at ombryde med Refit senere:
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
});
// Base HttpClient konfiguration
builder.Services.AddHttpClient("MobileApi", client =>
{
client.BaseAddress = new Uri("https://api.example.com/v1/");
client.Timeout = TimeSpan.FromSeconds(30);
client.DefaultRequestHeaders.Add("User-Agent", "MobileTechLead/1.0");
});
return builder.Build();
}
Bemærk at BaseAddress ender med en skråstreg. Uden den vil relative URI'er i Refit blive tolket forkert (og du får en time i debuggeren gratis). Timeout på 30 sekunder er min standard for mobile netværk; hvis dit API kører 3G-scenarier, kan du overveje 60 sekunder, men vær opmærksom på, at brugere opgiver længe før det.
Refit: type-safe klienter uden boilerplate
Refit lader dig deklarere API-endpoints som et interface med attributter, og genererer implementeringen ved kompilering. Det fjerner manuel URL-formatering, JSON-serialisering og fejlkontrol fra din view model-kode. Definér først din model og dit interface:
public record Product(int Id, string Name, decimal Price, string ImageUrl);
public record ProductPage(IReadOnlyList<Product> Items, int Total, int Page);
public interface IProductApi
{
[Get("/products")]
Task<ProductPage> GetProductsAsync(
[Query] int page = 1,
[Query] int pageSize = 20,
CancellationToken ct = default);
[Get("/products/{id}")]
Task<Product> GetProductAsync(int id, CancellationToken ct = default);
[Post("/products")]
Task<Product> CreateProductAsync(
[Body] Product product,
CancellationToken ct = default);
[Multipart]
[Post("/products/{id}/image")]
Task UploadImageAsync(
int id,
[AliasAs("file")] StreamPart image,
CancellationToken ct = default);
}
Registrér Refit-klienten sammen med din navngivne HttpClient:
Din view model modtager nu IProductApi via constructor injection, helt fri for HTTP-detaljer, hvilket gør den trivielt testbar. Se Refit-projektets officielle dokumentation for fulde attribut-oversigter, herunder [Header], [QueryUriFormat] og typede fejl-modeller via ApiException. Hvis du har brug for at genopfriske dependency injection-mønstre først, dækker vores guide til dependency injection i .NET MAUI alle service-livscyklusser i detaljer.
Resilience med Polly og retry-strategier
Mobile netværk fejler konstant: en tunnel, en overfyldt celletårn, en Wi-Fi-overgang. En stabil API-klient antager fejl som normen og reagerer med eksponentiel back-off. Microsoft.Extensions.Http.Resilience pakker Polly v8 med sensible standarder, som du kan tilføje til enhver HttpClient med én linje:
Standardhandler'en kombinerer fem strategier: timeout pr. forsøg, samlet timeout, retry med jitter, circuit breaker og rate limiter. Jitter er kritisk i mobile scenarier. Uden den vil hundredvis af klienter forsøge igen samtidig efter en netværksafbrydelse og forværre problemet.
Til produktion anbefaler jeg at logge circuit-breaker-transitioner via ILogger. Det er dit tidligste signal om et nedstrøms API-outage. Polly's telemetri integrerer med Microsoft.Extensions.Diagnostics, så du får dette gratis, hvis du allerede har opsat structured logging.
DelegatingHandler til authentication og logging
Bearer-tokens hører ikke hjemme i hvert enkelt Refit-kald. Brug en DelegatingHandler, som opsnapper alle forespørgsler for din klient og tilføjer headers centralt. Dette er også det rette sted til at håndtere token-fornyelse på 401-responses:
public sealed class AuthHeaderHandler : DelegatingHandler
{
private readonly ITokenProvider _tokens;
public AuthHeaderHandler(ITokenProvider tokens)
{
_tokens = tokens;
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken ct)
{
var token = await _tokens.GetAccessTokenAsync(ct);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await base.SendAsync(request, ct);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
token = await _tokens.RefreshAsync(ct);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
response.Dispose();
response = await base.SendAsync(request, ct);
}
return response;
}
}
Tokens bør gemmes i SecureStorage, aldrig i Preferences eller ren tekst. Vores guide til sikkerhed i .NET MAUI dækker dette i detaljer, inklusive biometrisk beskyttelse af refresh tokens.
iOS- og Android-platformkonfiguration
Både iOS og Android har platform-specifikke krav til HTTP-trafik i 2026. På iOS blokerer App Transport Security (ATS) al HTTP-trafik uden TLS 1.2+. Til produktion er det præcis hvad du vil have, men til lokal udvikling mod http://localhost:5000 skal du tilføje en undtagelse i Platforms/iOS/Info.plist:
På Android skal du eksplicit tillade cleartext-trafik pr. domæne via en network security config. Opret Platforms/Android/Resources/xml/network_security_config.xml:
Reference filen fra AndroidManifest.xml via <application android:networkSecurityConfig="@xml/network_security_config">. Android-emulatoren bruger 10.0.2.2 som alias for host-maskinens localhost, en detalje der har kostet mig flere timer over årene. Husk det, seriøst.
På Android bør du også opgradere til SocketsHttpHandler (default fra .NET 8) i stedet for den ældre Xamarin-handler. Det giver HTTP/2, connection pooling og bedre timeout-håndtering. .NET MAUI bruger den korrekte handler by default siden 8.0, men hvis du migrerer fra Xamarin.Forms, bør du eksplicit sætte <UseNativeHttpHandler>false</UseNativeHttpHandler> i din .csproj.
Håndtering af offline-tilstand og connectivity
En mobile-first API-klient skal reagere på ændringer i netværkstilstand. IConnectivity fra Microsoft.Maui.Essentials giver både en synkron tilstand og en event:
Dette mønster (stale-while-revalidate) er min standard. Vis cached data hurtigt, opdatér i baggrunden, og fald tilbage til cache ved API-fejl. Til skrive-operationer bruger jeg en outbox-tabel i SQLite, hvor pending mutations opbevares indtil netværket vender tilbage. Vores guide til SQLite og EF Core i .NET MAUI viser hvordan du opsætter den lokale store.
Test af dine API-klienter
Fordi din view model afhænger af IProductApi (interface) og ikke HttpClient (concrete), er unit tests trivielle:
[Fact]
public async Task LoadProducts_populates_collection()
{
var api = Substitute.For<IProductApi>();
api.GetProductsAsync(Arg.Any<int>(), Arg.Any<int>(), Arg.Any<CancellationToken>())
.Returns(new ProductPage(new[] { new Product(1, "Test", 99m, "img.jpg") }, 1, 1));
var vm = new ProductListViewModel(api);
await vm.LoadCommand.ExecuteAsync(null);
Assert.Single(vm.Products);
}
Til integration tests mod en fake HTTP-server bruger jeg WireMock.Net, som lader dig scripte responses inklusive fejl-scenarier. Det er langt mere realistisk end at mocke Refit-interfacet, fordi du også får dine DelegatingHandlers og Polly-strategier med i testen. Vores komplette teststrategi for .NET MAUI dækker både unit-, integration- og UI-tests. Se også Microsofts vejledning om test af IHttpClientFactory.
Ofte stillede spørgsmål
Hvad er forskellen mellem HttpClient og Refit i .NET MAUI?
HttpClient er den lav-niveau .NET-klasse til at sende HTTP-forespørgsler manuelt. Refit er et bibliotek der genererer en type-safe klient-implementering fra et interface, så du deklarerer endpoints med attributter i stedet for at bygge HttpRequestMessage-objekter selv. Refit bruger stadig HttpClient internt, så det er egentlig et abstraktionslag ovenpå.
Kan man bruge IHttpClientFactory i .NET MAUI?
Ja, IHttpClientFactory er fuldt understøttet i .NET MAUI via Microsoft.Extensions.Http-pakken. Registrér dine klienter i MauiProgram.cs med builder.Services.AddHttpClient(), og inject enten IHttpClientFactory eller en typed client i dine services.
Hvordan tilføjer man authentication headers til alle API-kald?
Opret en klasse der arver fra DelegatingHandler, overskriv SendAsync og tilføj request.Headers.Authorization. Registrér den derefter på din HttpClient med .AddHttpMessageHandler<YourHandler>(). Dette centraliserer auth-logik og lader dig håndtere 401-responses med token-fornyelse ét sted.
Hvordan implementerer man retry-logik med Polly i .NET MAUI?
Installér Microsoft.Extensions.Http.Resilience, og tilføj .AddStandardResilienceHandler() til din klient-registrering. Standardhandler'en giver retry med eksponentiel back-off og jitter, timeouts og circuit breaker, og alt kan tilpasses via en options-callback uden at ændre din API-kode.
Skal man bruge System.Text.Json eller Newtonsoft.Json med Refit?
Brug System.Text.Json. Det er default i Refit 8, betydeligt hurtigere, og fylder mindre i din app. Newtonsoft.Json er kun nødvendigt hvis du bruger avancerede features som custom JsonConverter-hierarkier eller [JsonExtensionData], som System.Text.Json først for nyligt har fået fuld paritet på.
Lær at bygge en hurtig, sikker og vedligeholdbar lokal database i .NET MAUI med enten sqlite-net-pcl eller Entity Framework Core 9. Inkluderer setup, repository-mønster, migrationer, SQLCipher-kryptering og performance-tips med fungerende C#-eksempler.
Handlers afløser Xamarin Renderers i .NET MAUI. Lær at bygge en custom Entry med platform-specifik kode til iOS (UIKit) og Android (AppCompat), inklusive registrering, lifecycle og memory leak-håndtering.