Linger.HttpClient.Contracts
0.4.0-alpha
See the version list below for details.
dotnet add package Linger.HttpClient.Contracts --version 0.4.0-alpha
NuGet\Install-Package Linger.HttpClient.Contracts -Version 0.4.0-alpha
<PackageReference Include="Linger.HttpClient.Contracts" Version="0.4.0-alpha" />
<PackageVersion Include="Linger.HttpClient.Contracts" Version="0.4.0-alpha" />
<PackageReference Include="Linger.HttpClient.Contracts" />
paket add Linger.HttpClient.Contracts --version 0.4.0-alpha
#r "nuget: Linger.HttpClient.Contracts, 0.4.0-alpha"
#:package Linger.HttpClient.Contracts@0.4.0-alpha
#addin nuget:?package=Linger.HttpClient.Contracts&version=0.4.0-alpha&prerelease
#tool nuget:?package=Linger.HttpClient.Contracts&version=0.4.0-alpha&prerelease
Linger.HttpClient.Contracts
Table of Contents
- Overview
- Installation
- Core Components
- Usage Guide
- Dependency Injection Integration
- Polly Policies Integration
- Advanced Features
- Best Practices
- Implementation Projects
Overview
Linger HTTP Client Ecosystem
The Linger HTTP client ecosystem consists of three main components:
- Linger.HttpClient.Contracts: Interfaces and abstract classes defining standard contracts for HTTP operations (this project)
- Linger.HttpClient.Standard: Implementation based on .NET standard HttpClient
- Linger.HttpClient.Flurl: Fluent API implementation based on Flurl.Http
Linger.HttpClient.Contracts defines standard interfaces and contracts for HTTP client operations and serves as the foundation for Linger HTTP client implementations. By using unified contracts, you can easily switch between different HTTP client implementations without modifying your business code.
Features
- Strongly typed HTTP client interfaces
- Support for various HTTP methods (GET, POST, PUT, DELETE)
- File upload capabilities (simplified with unified MultipartHelper)
- Request/response interception system
- Customizable HTTP options
- Paged result support
- Automatic retry mechanism
- User-friendly error handling
- Built-in compression support
- Performance monitoring and statistics
Supported .NET Versions
- .NET Standard 2.0+
- .NET Framework 4.6.2+
- .NET 6.0+
- .NET 8.0/9.0
Recent Improvements
1. Enhanced Interceptor System
The newly designed interceptor system is consistently applied across all client implementations:
// Define an interceptor
public class LoggingInterceptor : IHttpClientInterceptor
{
public async Task<HttpRequestMessage> OnRequestAsync(HttpRequestMessage request)
{
Console.WriteLine($"Sending request: {request.Method} {request.RequestUri}");
return request;
}
public async Task<HttpResponseMessage> OnResponseAsync(HttpResponseMessage response)
{
Console.WriteLine($"Received response: {(int)response.StatusCode}");
return response;
}
}
// Add the interceptor
client.AddInterceptor(new LoggingInterceptor());
2. Default Interceptor Factory
The new DefaultInterceptorFactory automatically creates appropriate interceptors based on configuration:
// Factory creates interceptors based on HttpClientOptions configuration
var interceptors = DefaultInterceptorFactory.CreateStandardInterceptors(options);
foreach (var interceptor in the interceptors)
{
client.AddInterceptor(interceptor);
}
3. Built-in Compression Support
HTTP compression is supported automatically without additional configuration:
// CompressionInterceptor is automatically applied to all clients
var client = factory.CreateClient("https://api.example.com");
// Requests automatically include Accept-Encoding header with gzip and deflate
var response = await client.GetAsync<UserData>("api/users/1");
4. Unified File Upload Handling
File uploads are simplified using MultipartHelper:
// File upload example
byte[] fileData = File.ReadAllBytes("document.pdf");
var formData = new Dictionary<string, string> { { "description", "Test document" } };
// All client implementations handle file uploads in a unified way
var response = await client.CallApi<UploadResult>(
"api/files/upload",
HttpMethodEnum.Post,
formData,
fileData,
"document.pdf"
);
5. Advanced Performance Monitoring
Built-in performance monitoring provides detailed HTTP request statistics:
// Get performance stats for a specific endpoint
var stats = HttpClientMetrics.Instance.GetEndpointStats("api/users");
Console.WriteLine($"Average response time: {stats.AverageResponseTime}ms");
Console.WriteLine($"Success rate: {stats.SuccessRate * 100}%");
Console.WriteLine($"Active requests: {stats.ActiveRequests}");
Installation
Via NuGet
To use IHttpClient and its implementations, you need to install one of the following NuGet packages:
Option 1: Install Basic HTTP Client
# Install interfaces and contracts
dotnet add package Linger.HttpClient.Contracts
# Install implementation based on standard HttpClient
dotnet add package Linger.HttpClient.Standard
Option 2: Install Flurl-based HTTP Client
# Install interfaces and contracts
dotnet add package Linger.HttpClient.Contracts
# Install Flurl-based implementation
dotnet add package Linger.HttpClient.Flurl
Option 3: Install Both Implementations (use as needed)
dotnet add package Linger.HttpClient.Contracts
dotnet add package Linger.HttpClient.Standard
dotnet add package Linger.HttpClient.Flurl
Using Package Manager Console
# Install interfaces and contracts
Install-Package Linger.HttpClient.Contracts
# Install implementation
Install-Package Linger.HttpClient.Standard
# or
Install-Package Linger.HttpClient.Flurl
Core Components
Core Interfaces
IHttpClient
The core HTTP client interface that defines standard methods for all HTTP operations:
public interface IHttpClient
{
// Basic HTTP methods
Task<ApiResult<T>> CallApi<T>(string url, object? queryParams = null, int? timeout = null,
CancellationToken cancellationToken = default);
Task<ApiResult<T>> CallApi<T>(string url, HttpMethodEnum method, object? postData = null,
object? queryParams = null, int? timeout = null, CancellationToken cancellationToken = default);
// File upload and form submission
Task<ApiResult<T>> CallApi<T>(string url, HttpMethodEnum method, IDictionary<string, string>? postData,
byte[] fileData, string filename, int? timeout = null, CancellationToken cancellationToken = default);
// Configuration and extension
void SetToken(string token);
void AddHeader(string name, string value);
void AddInterceptor(IHttpClientInterceptor interceptor);
HttpClientOptions Options { get; }
}
IHttpClientInterceptor
Request/response interceptor interface that allows adding custom logic before and after requests:
public interface IHttpClientInterceptor
{
Task<HttpRequestMessage> OnRequestAsync(HttpRequestMessage request);
Task<HttpResponseMessage> OnResponseAsync(HttpResponseMessage response);
}
IHttpClientFactory
HTTP client factory interface for creating and managing HTTP client instances:
public interface IHttpClientFactory
{
IHttpClient CreateClient(string baseUrl);
IHttpClient CreateClient(string baseUrl, Action<HttpClientOptions> configureOptions);
IHttpClient GetOrCreateClient(string name);
void RegisterClient(string name, string baseUrl, Action<HttpClientOptions>? configureOptions = null);
}
Core Models
ApiResult<T>
Unified result wrapper for API calls:
public class ApiResult<T>
{
// Response data
public T Data { get; set; } = default!;
// HTTP status code
public HttpStatusCode? StatusCode { get; set; }
// Error information
public ErrorObj? Errors { get; set; }
public string? ErrorMsg { get; set; }
// Helper properties
public bool IsSuccess => StatusCode.HasValue && (int)StatusCode.Value >= 200 && (int)StatusCode.Value < 300;
public bool IsUnauthorized => StatusCode == HttpStatusCode.Unauthorized;
}
ApiPagedResult<T>
Paged API result wrapper:
public class ApiPagedResult<T>
{
// Current page data
public List<T> Data { get; set; } = default!;
// Pagination information
public int TotalCount { get; set; }
public int Page { get; set; }
public int PageCount { get; set; }
// Helper properties
public bool HasData => Data != null && Data.Count > 0;
public bool HasNextPage => Page < PageCount;
}
HttpClientOptions
HTTP client configuration options:
public class HttpClientOptions
{
// Timeout settings
public int DefaultTimeout { get; set; } = 30;
// Retry settings
public bool EnableRetry { get; set; } = false;
public int MaxRetryCount { get; set; } = 3;
public int RetryInterval { get; set; } = 1000;
// Headers
public Dictionary<string, string> DefaultHeaders { get; set; } = new();
}
Design Philosophy
Interface Segregation Principle
Linger.HttpClient.Contracts follows the interface segregation principle, separating interfaces with different responsibilities:
- IHttpClient: Defines basic HTTP request operations
- IHttpClientInterceptor: Focuses on intercepting and modifying requests/responses
- IHttpClientFactory: Responsible for client instance creation and management
Extensibility
The interceptor mechanism is a core extension point, allowing for features such as:
- Request/response logging
- Authentication token automatic refresh
- Request retry and error handling
- Response caching
- Performance monitoring
Unified Response Handling
All HTTP responses are wrapped in an ApiResult<T>, providing a consistent handling pattern:
- Unified success/failure determination
- Type-safe data access
- Structured error information
Usage Guide
Basic Usage
This is a contracts library that defines interfaces and abstract classes. For implementation, use Linger.HttpClient.Standard or Linger.HttpClient.Flurl.
Creating a Client
// Create HTTP client
var client = new Linger.HttpClient.Standard.StandardHttpClient("https://api.example.com");
Sending GET Requests
// GET request
var result = await client.CallApi<UserData>("users/1");
// Handle response
if (result.IsSuccess)
{
var user = result.Data;
Console.WriteLine($"User: {user.Name}");
}
else
{
Console.WriteLine($"Error: {result.ErrorMsg}");
}
Sending POST Requests
// POST request
var postResult = await client.CallApi<UserData>("users", HttpMethodEnum.Post,
new { Name = "John", Email = "john@example.com" });
Requests with Query Parameters
// GET request with query parameters
var queryResult = await client.CallApi<List<UserData>>("users",
new { page = 1, pageSize = 10 });
Extension Features
The library also provides some extension methods for a more convenient API experience:
// GET request simplification
var user = await client.GetAsync<UserData>("api/users/1");
// POST request simplification
var newUser = await client.PostAsync<UserData>("api/users", new { Name = "John Doe" });
// Paged request simplification
var pagedUsers = await client.GetPagedAsync<UserData>("api/users", new { page = 1, pageSize = 20 });
File Upload
// File upload
byte[] fileData = File.ReadAllBytes("document.pdf");
var formData = new Dictionary<string, string>
{
{ "description", "Sample document" },
{ "category", "reports" }
};
var uploadResult = await client.CallApi<UploadResponse>(
"files/upload",
HttpMethodEnum.Post,
formData,
fileData,
"document.pdf"
);
Interceptor System
Linger.HttpClient.Contracts provides several built-in interceptors to enhance HTTP client functionality:
Interceptor Usage Pattern
// Define interceptor
public class LoggingInterceptor : IHttpClientInterceptor
{
public Task<HttpRequestMessage> OnRequestAsync(HttpRequestMessage request)
{
Console.WriteLine($"Sending request: {request.Method} {request.RequestUri}");
return Task.FromResult(request);
}
public Task<HttpResponseMessage> OnResponseAsync(HttpResponseMessage response)
{
Console.WriteLine($"Received response: {(int)response.StatusCode}");
return Task.FromResult(response);
}
}
// Add interceptor
client.AddInterceptor(new LoggingInterceptor());
Built-in Interceptors
Retry Interceptor
// Enable retry with simple configuration
client.Options.EnableRetry = true;
client.Options.MaxRetryCount = 3;
client.Options.RetryInterval = 1000; // milliseconds
// Or manually add a custom retry interceptor
var retryInterceptor = new RetryInterceptor(
options,
response => response.StatusCode == HttpStatusCode.ServiceUnavailable
);
client.AddInterceptor(retryInterceptor);
Compression Interceptor
// Compression interceptor is automatically added by DefaultInterceptorFactory
// Or add it manually
client.AddInterceptor(new CompressionInterceptor());
Caching Interceptor
// Create and configure caching interceptor
var cachingInterceptor = new CachingInterceptor(
defaultCacheDuration: TimeSpan.FromMinutes(10)
);
client.AddInterceptor(cachingInterceptor);
Factory Usage Pattern
// Create factory
var factory = new DefaultHttpClientFactory();
// Register named client
factory.RegisterClient("users-api", "https://users.example.com", options => {
options.DefaultTimeout = 20;
options.EnableRetry = true;
});
// Get named client
var client = factory.GetOrCreateClient("users-api");
Dependency Injection Integration
IHttpClient can be easily integrated with dependency injection containers.
Basic Registration
// Using Linger.HttpClient.Standard implementation
services.AddScoped<IHttpClient>(provider =>
new StandardHttpClient("https://api.example.com"));
// Or using Linger.HttpClient.Flurl implementation
services.AddScoped<IHttpClient>(provider =>
new FlurlHttpClient("https://api.example.com"));
Configuring Options
services.AddScoped<IHttpClient>(provider =>
{
var client = new StandardHttpClient("https://api.example.com");
// Configure options
client.Options.DefaultTimeout = 30; // Set default timeout to 30 seconds
client.Options.EnableRetry = true; // Enable retry
client.Options.MaxRetryCount = 3; // Maximum retry count
// Add default headers
client.AddHeader("User-Agent", "Linger HttpClient");
client.AddHeader("Accept", "application/json");
// Add request/response interceptors
client.AddInterceptor(new LoggingInterceptor());
return client;
});
Using in Services
public class MyService
{
private readonly IHttpClient _httpClient;
public MyService(IHttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<UserData> GetUserDataAsync(int userId)
{
var result = await _httpClient.CallApi<UserData>($"users/{userId}");
if (result.IsSuccess)
{
return result.Data;
}
throw new Exception($"Failed to get user data: {result.ErrorMsg}");
}
}
Using Microsoft's HttpClientFactory
In addition to the methods above, you can also use Microsoft's HttpClientFactory to manage HTTP client lifecycle, avoiding common pitfalls such as DNS changes issues and socket exhaustion:
// 1. Basic registration
services.AddHttpClient<IHttpClient, StandardHttpClient>(client =>
{
client.BaseAddress = new Uri("https://api.example.com");
client.Timeout = TimeSpan.FromSeconds(30);
client.DefaultRequestHeaders.Add("User-Agent", "Linger HttpClient");
});
// 2. Using named clients with options and interceptors
services.AddHttpClient("MyApi", client =>
{
client.BaseAddress = new Uri("https://api.example.com");
client.Timeout = TimeSpan.FromSeconds(30);
})
.AddTypedClient<IHttpClient>((httpClient, serviceProvider) =>
{
// Create client instance
var client = new StandardHttpClient(httpClient);
// Configure options
client.Options.DefaultTimeout = 30;
client.Options.EnableRetry = true;
client.Options.MaxRetryCount = 3;
// Add interceptors
var logger = serviceProvider.GetRequiredService<ILogger<IHttpClient>>();
client.AddInterceptor(new LoggingInterceptor(log => logger.LogInformation(log)));
client.AddInterceptor(new RetryInterceptor(client.Options));
return client;
});
// 3. Adding message handlers and policies
services.AddHttpClient<IHttpClient, StandardHttpClient>(client =>
{
client.BaseAddress = new Uri("https://api.example.com");
})
.AddPolicyHandler(GetRetryPolicy()) // Add Polly retry policy
.AddHttpMessageHandler(() => new CustomMessageHandler()); // Add custom handler
// Helper method to get Polly policy
private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.TooManyRequests)
.WaitAndRetryAsync(3, retryAttempt =>
TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
Using HttpClientFactory in Services
public class ApiService
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly IHttpClient _client;
public ApiService(
IHttpClientFactory httpClientFactory,
IHttpClient client) // Default injected client
{
_httpClientFactory = httpClientFactory;
_client = client;
}
public async Task<UserData> GetNamedClientUserAsync(int userId)
{
// Get typed named client
var apiClient = _httpClientFactory.CreateClient("MyApi")
.GetTypedClient<IHttpClient>();
var result = await apiClient.CallApi<UserData>($"users/{userId}");
return result.Data;
}
}
Multiple Instance Configuration
If you need to use multiple HTTP clients with different configurations, you can use named injection:
services.AddScoped<IHttpClient>(provider =>
new StandardHttpClient("https://api1.example.com"));
services.AddKeyedScoped<IHttpClient>("api2", (provider, key) =>
new StandardHttpClient("https://api2.example.com"));
// Access through IServiceProvider when using
var api2Client = serviceProvider.GetKeyedService<IHttpClient>("api2");
Polly Policies Integration
Polly is a powerful .NET resilience and transient-fault-handling library that can be seamlessly integrated with both Linger.HttpClient and Microsoft's HttpClientFactory.
Common Policy Types
- Retry Policies - Automatically retry failed requests
- Circuit Breaker Policies - Temporarily stop attempts when the system detects multiple failures
- Timeout Policies - Set timeout limits for requests
- Fallback Policies - Provide alternative responses when requests fail
- Policy Wraps - Combine multiple policies together
Configuration Examples
Adding Polly Support
# Install Polly integration package for HttpClientFactory
dotnet add package Microsoft.Extensions.Http.Polly
Retry Policy Example
services.AddHttpClient<IHttpClient, StandardHttpClient>(client =>
{
client.BaseAddress = new Uri("https://api.example.com");
})
.AddPolicyHandler(GetRetryPolicy());
// Define retry policy
private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError() // Handles network errors and 5xx, 408 responses
.OrResult(msg => msg.StatusCode == HttpStatusCode.TooManyRequests) // Also handle 429 responses
.WaitAndRetryAsync(
retryCount: 3, // Retry 3 times
sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), // Exponential backoff: 2, 4, 8 seconds
onRetry: (outcome, timespan, retryCount, context) =>
{
// Log retry information
Console.WriteLine($"Attempting retry {retryCount}, waiting {timespan.TotalSeconds} seconds");
});
}
Circuit Breaker Policy Example
services.AddHttpClient<IHttpClient, StandardHttpClient>(client =>
{
client.BaseAddress = new Uri("https://api.example.com");
})
.AddPolicyHandler(GetCircuitBreakerPolicy());
// Define circuit breaker policy
private static IAsyncPolicy<HttpResponseMessage> GetCircuitBreakerPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.CircuitBreakerAsync(
handledEventsAllowedBeforeBreaking: 5, // Break after 5 failures
durationOfBreak: TimeSpan.FromSeconds(30), // Stay open for 30 seconds
onBreak: (ex, breakDelay) =>
{
// Circuit is now open
Console.WriteLine($"Circuit breaker opened, will attempt to reset after {breakDelay.TotalSeconds} seconds");
},
onReset: () =>
{
// Circuit is now closed again
Console.WriteLine("Circuit breaker reset, service recovered");
});
}
Combining Multiple Policies
services.AddHttpClient<IHttpClient, StandardHttpClient>(client =>
{
client.BaseAddress = new Uri("https://api.example.com");
})
.AddPolicyHandler(GetRetryPolicy()) // Apply retry policy first
.AddPolicyHandler(GetCircuitBreakerPolicy()); // Then circuit breaker policy
// Alternatively, explicitly combine using PolicyWrap
private static IAsyncPolicy<HttpResponseMessage> GetCombinedPolicy()
{
return Policy.WrapAsync(GetRetryPolicy(), GetCircuitBreakerPolicy());
}
Combining with Linger Interceptors
Linger's interceptor system and Polly policies can be combined for greater functionality:
// 1. First configure Polly policies
services.AddHttpClient("resilient-api", client =>
{
client.BaseAddress = new Uri("https://api.example.com");
})
.AddPolicyHandler(GetRetryPolicy())
.AddTypedClient<IHttpClient>((httpClient, serviceProvider) =>
{
// 2. Create client instance
var client = new StandardHttpClient(httpClient);
// 3. Add Linger interceptors for scenarios Polly can't handle
client.AddInterceptor(new LoggingInterceptor(
log => serviceProvider.GetRequiredService<ILogger<IHttpClient>>().LogInformation(log)
));
client.AddInterceptor(new TokenRefreshInterceptor(
serviceProvider.GetRequiredService<ITokenService>()
));
return client;
});
Differences Between Polly Policies and Linger Retry Mechanism
Different Levels of Operation:
- Polly policies operate at the underlying HttpClient level, handling retries at the network request level
- Linger's RetryInterceptor operates at the application layer, with access to the complete response content
Feature Range:
- Polly provides a more comprehensive set of resilience policies (retry, circuit breaker, timeout, etc.)
- Linger interceptors focus more on business logic handling (e.g., token refreshing)
Usage Recommendations:
- Use Polly for handling network-level and basic HTTP errors (timeouts, 5xx errors, etc.)
- Use Linger interceptors for handling business-level errors and application-specific logic
Using both in combination can build more robust HTTP client applications.
Advanced Features
Custom Interceptors
public class LoggingInterceptor : IHttpClientInterceptor
{
private readonly ILogger _logger;
public LoggingInterceptor(ILogger logger)
{
_logger = logger;
}
public async Task<HttpRequestMessage> OnRequestAsync(HttpRequestMessage request)
{
_logger.LogInformation($"Request: {request.Method} {request.RequestUri}");
return request;
}
public async Task<HttpResponseMessage> OnResponseAsync(HttpResponseMessage response)
{
_logger.LogInformation($"Response: {(int)response.StatusCode} {response.ReasonPhrase}");
return response;
}
}
Error Handling
public async Task<T> ExecuteApiCall<T>(string endpoint)
{
try
{
var result = await _httpClient.CallApi<T>(endpoint);
if (!result.IsSuccess)
{
if (result.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
await RefreshTokenAsync();
// Retry the request
return await ExecuteApiCall<T>(endpoint);
}
if (result.Errors != null)
{
// Handle detailed error information
throw new ApiException(result.Errors);
}
throw new ApiException(result.ErrorMsg);
}
return result.Data;
}
catch (Exception ex) when (ex is HttpRequestException || ex is TaskCanceledException)
{
// Handle network errors
throw new NetworkException("Network request failed", ex);
}
}
Performance Monitoring
Built-in performance monitoring helps identify and resolve performance issues:
// Record start before sending request
var requestId = HttpClientMetrics.Instance.StartRequest(url);
try
{
// Execute HTTP request
var result = await _httpClient.CallApi<UserData>(url);
// Record successful completion
HttpClientMetrics.Instance.EndRequest(url, requestId, result.IsSuccess);
return result.Data;
}
catch
{
// Record failure
HttpClientMetrics.Instance.EndRequest(url, requestId, false);
throw;
}
// Get performance stats for a specific endpoint
var stats = HttpClientMetrics.Instance.GetEndpointStats("api/users");
Console.WriteLine($"Average response time: {stats.AverageResponseTime}ms");
Console.WriteLine($"Success rate: {stats.SuccessRate * 100}%");
// Get stats for all endpoints
var allStats = HttpClientMetrics.Instance.GetAllStats();
foreach (var entry in allStats)
{
Console.WriteLine($"Endpoint: {entry.Key}, Requests: {entry.Value.TotalRequests}");
}
Performance metrics include:
- Total request count
- Successful/failed request count
- Success rate
- Average/min/max response time
- Currently active requests
Best Practices
Instance Management
- Recommended: Use dependency injection container to manage HttpClient lifecycle
- Avoid creating new instances for each request which can lead to port exhaustion
- Use
HttpClientFactoryor dependency injection framework
Request Optimization
- Set reasonable timeout values to prevent requests from hanging indefinitely
- Use streaming for large responses instead of loading them entirely into memory
- Use compression to reduce network load
Exception Handling
- Always catch and handle HTTP request exceptions
- Implement backoff strategies for server overload situations
- Use circuit breaker pattern to prevent cascading failures
Implementation Projects
For detailed usage and examples, refer to the documentation of specific implementation projects:
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 is compatible. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.7.2
- Linger.Utils (>= 0.4.0-alpha)
-
.NETStandard 2.0
- Linger.Utils (>= 0.4.0-alpha)
-
net8.0
- Linger.Utils (>= 0.4.0-alpha)
-
net9.0
- Linger.Utils (>= 0.4.0-alpha)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Linger.HttpClient.Contracts:
| Package | Downloads |
|---|---|
|
Linger.HttpClient.Standard
A lightweight implementation of Linger.HttpClient.Contracts using standard .NET HttpClient. Provides robust HTTP request handling with automatic retries, timeout management, and typed response parsing. Seamlessly integrates with .NET's HttpClientFactory for optimal connection management. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.9.8 | 151 | 10/14/2025 |
| 0.9.7-preview | 144 | 10/13/2025 |
| 0.9.6-preview | 125 | 10/12/2025 |
| 0.9.5 | 138 | 9/28/2025 |
| 0.9.4-preview | 161 | 9/25/2025 |
| 0.9.3-preview | 201 | 9/22/2025 |
| 0.9.1-preview | 290 | 9/16/2025 |
| 0.9.0-preview | 120 | 9/12/2025 |
| 0.8.5-preview | 220 | 8/31/2025 |
| 0.8.4-preview | 339 | 8/25/2025 |
| 0.8.3-preview | 199 | 8/20/2025 |
| 0.8.2-preview | 229 | 8/4/2025 |
| 0.8.1-preview | 132 | 7/30/2025 |
| 0.8.0-preview | 590 | 7/22/2025 |
| 0.7.2 | 210 | 6/3/2025 |
| 0.7.1 | 216 | 5/21/2025 |
| 0.7.0 | 209 | 5/19/2025 |
| 0.6.0-alpha | 216 | 4/28/2025 |
| 0.5.0-alpha | 217 | 4/10/2025 |
| 0.4.0-alpha | 192 | 4/1/2025 |