PowerCSharp.Extensions.AspNetCore provides ASP.NET Core specific extension methods that require ASP.NET Core dependencies. This package focuses on configuration management, web utilities, and HTTP operations that are specifically designed for modern ASP.NET Core applications.
Recent Improvements (v0.3.0):
- Package Separation: Extracted from PowerCSharp.Extensions for cleaner dependency management
- Enhanced Performance: Optimized HTTP operations and configuration handling
- Better Integration: Improved ASP.NET Core dependency injection support
- Updated Dependencies: All Microsoft.Extensions packages updated to .NET 8.0 compatible versions
- Improved Documentation: Comprehensive usage examples and best practices
- .NET 8.0 - Leverages the latest ASP.NET Core features and optimizations
- PowerCSharp.Core v0.3.0 - Shared interfaces and base functionality
- Microsoft.AspNetCore.WebUtilities v8.0.8 - URL query string manipulation and web utilities
- Microsoft.Extensions.Configuration.Abstractions v8.0.0 - Configuration support
- Microsoft.Extensions.Configuration.Binder v8.0.0 - Configuration binding
- Microsoft.Extensions.DependencyInjection v8.0.0 - Dependency injection support
- Microsoft.Extensions.Options v8.0.0 - Options pattern support
- Package Compatibility: Resolved NuGet package compatibility issues for .NET 8.0
- Dependency Updates: Updated all Microsoft.Extensions packages to v8.0.x for full .NET 8.0 compatibility
- Build Improvements: Enhanced package generation with symbol packages
Contains extension methods for configuration operations in ASP.NET Core applications.
Contains extension methods for network operations, HTTP utilities, and URI manipulation.
Located in: PowerCSharp.Extensions.AspNetCore.Configuration
Gets options from IConfiguration object using the specified configuration section path.
Parameters:
configuration(IConfiguration): The IConfiguration object to read fromsectionPath(string): The configuration section path to use
Returns:
TOptions: The configured options object
Type Parameters:
TOptions: The type of options to retrieve. Must implement IAppOptions
Exceptions:
ArgumentNullException: Thrown when configuration is nullArgumentException: Thrown when sectionPath is null or whitespaceInvalidOperationException: Thrown when configuration binding fails
Example:
using PowerCSharp.Extensions.AspNetCore;
using Microsoft.Extensions.Configuration;
public class AppSettings : IAppOptions
{
public string ApiUrl { get; set; } = "";
public int MaxRetries { get; set; } = 3;
}
var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var settings = configuration.GetOptions<AppSettings>("AppSettings");Located in: PowerCSharp.Extensions.AspNetCore.Net
Adds the specified parameter to the query string of the URI.
Parameters:
url(Uri): The base URI to add the parameter toparameterName(string): The name of the parameter to addparameterValue(string): The value for the parameter to add
Returns:
Uri: A new URI with the added parameter in the query string
Example:
using PowerCSharp.Extensions.AspNetCore;
var baseUrl = new Uri("https://api.example.com/users");
var urlWithPage = baseUrl.AddParameter("page", "2");
var urlWithFilters = urlWithPage.AddParameter("search", "john");
// Result: https://api.example.com/users?page=2&search=johnNotes:
- Automatically handles URL encoding of parameter values
- Preserves existing query string parameters
- Creates a new Uri instance (immutable operation)
Located in: PowerCSharp.Extensions.AspNetCore.Net
Creates a deep clone of the HttpRequestMessage including headers, content, and properties.
Parameters:
original(HttpRequestMessage): The original HttpRequestMessage to clone
Returns:
HttpRequestMessage: A new HttpRequestMessage instance with all headers, content, and properties copied
Exceptions:
ArgumentNullException: Thrown when the original request is null
Example:
using PowerCSharp.Extensions.AspNetCore;
using System.Net.Http;
var originalRequest = new HttpRequestMessage(HttpMethod.Get, "https://api.example.com/data");
originalRequest.Headers.Add("Authorization", "Bearer token123");
var clonedRequest = originalRequest.Clone();
// clonedRequest has the same method, URI, headers, and content as originalCreates a deep clone of the HttpRequestMessage asynchronously for better performance with large content.
Parameters:
original(HttpRequestMessage): The original HttpRequestMessage to clonecancellationToken(CancellationToken): A cancellation token to cancel the operation
Returns:
Task<HttpRequestMessage>: A task that represents the asynchronous operation, containing the cloned HttpRequestMessage
Exceptions:
ArgumentNullException: Thrown when the original request is null
Example:
using PowerCSharp.Extensions.AspNetCore;
using System.Net.Http;
var originalRequest = new HttpRequestMessage(HttpMethod.Post, "https://api.example.com/upload");
originalRequest.Content = new StringContent(largeJsonData, Encoding.UTF8, "application/json");
var clonedRequest = await originalRequest.CloneAsync();
// More efficient for large content as it reads asynchronouslyNotes:
- Essential for retry scenarios where HttpRequestMessage instances need to be recreated
- HttpRequestMessage instances can only be sent once per .NET guidelines
- Async version is recommended for requests with large content
Located in: PowerCSharp.Extensions.AspNetCore.Net
Determines if the HTTP status code indicates a successful request (2xx range).
Parameters:
statusCode(HttpStatusCode): The HTTP status code to check
Returns:
bool: True if the status code is in the 2xx range, otherwise false
Example:
using PowerCSharp.Extensions.AspNetCore;
using System.Net;
var response = await httpClient.GetAsync("https://api.example.com/data");
bool isSuccess = response.StatusCode.IsSuccessful(); // true for 200 OK, false for 404 Not FoundDetermines if the HTTP status code indicates a client error (4xx range).
Parameters:
statusCode(HttpStatusCode): The HTTP status code to check
Returns:
bool: True if the status code is in the 4xx range, otherwise false
Example:
bool isClientError = HttpStatusCode.BadRequest.IsClientError(); // true
bool isServerError = HttpStatusCode.InternalServerError.IsClientError(); // falseDetermines if the HTTP status code indicates a server error (5xx range).
Parameters:
statusCode(HttpStatusCode): The HTTP status code to check
Returns:
bool: True if the status code is in the 5xx range, otherwise false
Example:
bool isServerError = HttpStatusCode.InternalServerError.IsServerError(); // true
bool isClientError = HttpStatusCode.NotFound.IsServerError(); // falseDetermines if the HTTP status code indicates a redirect (3xx range).
Parameters:
statusCode(HttpStatusCode): The HTTP status code to check
Returns:
bool: True if the status code is in the 3xx range, otherwise false
Example:
bool isRedirect = HttpStatusCode.Found.IsRedirect(); // true
bool isSuccess = HttpStatusCode.OK.IsRedirect(); // falsepublic class DatabaseSettings : IAppOptions
{
public string ConnectionString { get; set; } = "";
public int CommandTimeout { get; set; } = 30;
public bool EnableRetry { get; set; } = true;
}
// In Startup.cs or Program.cs
public void ConfigureServices(IServiceCollection services)
{
var configuration = Configuration;
var dbSettings = configuration.GetOptions<DatabaseSettings>("DatabaseSettings");
services.Configure<DatabaseSettings>(configuration.GetSection("DatabaseSettings"));
// Use settings
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(dbSettings.ConnectionString));
}public class ResilientApiClient
{
private readonly HttpClient _httpClient;
private readonly ILogger<ResilientApiClient> _logger;
public async Task<T> GetWithRetryAsync<T>(string endpoint, int maxRetries = 3)
{
for (int attempt = 1; attempt <= maxRetries; attempt++)
{
try
{
var request = new HttpRequestMessage(HttpMethod.Get, endpoint);
var response = await _httpClient.SendAsync(request);
if (response.IsSuccessStatusCode)
{
return await response.Content.ReadFromJsonAsync<T>();
}
if (!response.StatusCode.IsServerError() && !response.StatusCode.IsClientError())
{
break; // Don't retry on success or redirect codes
}
_logger.LogWarning("Request failed with status {StatusCode}, attempt {Attempt}/{MaxRetries}",
response.StatusCode, attempt, maxRetries);
if (attempt < maxRetries)
{
await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)));
}
}
catch (Exception ex) when (attempt < maxRetries)
{
_logger.LogError(ex, "Request failed on attempt {Attempt}", attempt);
await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)));
}
}
throw new HttpRequestException($"Failed to get {endpoint} after {maxRetries} attempts");
}
}public class UrlBuilder
{
public Uri BuildSearchUrl(string baseUrl, SearchParameters parameters)
{
var uri = new Uri(baseUrl);
if (!string.IsNullOrEmpty(parameters.Query))
{
uri = uri.AddParameter("q", parameters.Query);
}
if (parameters.Page > 1)
{
uri = uri.AddParameter("page", parameters.Page.ToString());
}
if (parameters.PageSize != 20)
{
uri = uri.AddParameter("size", parameters.PageSize.ToString());
}
if (parameters.SortBy != "relevance")
{
uri = uri.AddParameter("sort", parameters.SortBy);
}
if (parameters.SortDescending)
{
uri = uri.AddParameter("order", "desc");
}
return uri;
}
}- Always validate options after loading them from configuration
- Use strongly-typed options classes that implement IAppOptions
- Provide sensible defaults for optional configuration values
- Use environment-specific configuration files for different deployment scenarios
- Use Clone() for retry scenarios - HttpRequestMessage can only be sent once
- Prefer CloneAsync() for large payloads to avoid blocking operations
- Check status code categories using the provided extension methods
- Implement proper error handling with exponential backoff for retries
- Chain AddParameter() calls for multiple query parameters
- Let the extension handle encoding - don't pre-encode parameter values
- Use Uri objects instead of string concatenation for URL building
- ConfigurationExtensions.GetOptions() uses efficient reflection-based binding
- UriExtensions.AddParameter() creates new Uri instances (immutable)
- HttpRequestMessageExtensions.Clone() performs deep copy of all properties
- HttpRequestMessageExtensions.CloneAsync() is more efficient for large content
All extension methods in PowerCSharp.Extensions.AspNetCore are thread-safe when used with immutable data structures. Configuration operations should be performed during application startup, and HTTP operations should use proper synchronization when shared across threads.
The extensions provide comprehensive error handling:
- ArgumentNullException for null parameters
- ArgumentException for invalid parameter values
- InvalidOperationException for configuration binding failures
- Meaningful error messages to aid debugging
- PowerCSharp.Core API Documentation - Core interfaces and models
- PowerCSharp.Extensions API Documentation - Cross-platform extensions
- Microsoft.Extensions.Configuration - Official configuration documentation
- Microsoft.AspNetCore.WebUtilities - Official web utilities documentation