Halifax.Http
5.1.1
dotnet add package Halifax.Http --version 5.1.1
NuGet\Install-Package Halifax.Http -Version 5.1.1
<PackageReference Include="Halifax.Http" Version="5.1.1" />
<PackageVersion Include="Halifax.Http" Version="5.1.1" />
<PackageReference Include="Halifax.Http" />
paket add Halifax.Http --version 5.1.1
#r "nuget: Halifax.Http, 5.1.1"
#:package Halifax.Http@5.1.1
#addin nuget:?package=Halifax.Http&version=5.1.1
#tool nuget:?package=Halifax.Http&version=5.1.1
Halifax Service Foundation
Simplistic libraries for complex projects. Halifax eliminates boilerplate in .NET API services — standardized responses, JWT auth, configuration, logging, and more — so you can focus on business logic.
| Package | NuGet |
|---|---|
| Halifax.Api | |
| Halifax.Core | |
| Halifax.Domain | |
| Halifax.Http | |
| Halifax.Excel |
Features
- Standardized API responses — consistent
ApiResponsewrapper for all endpoints - Exception handling — throw typed exceptions, get proper HTTP status codes automatically
- JWT authentication — configure auth in one line, create and validate tokens easily
- Environment configuration — load
.envfiles, map to strongly-typed classes/records - Input validation — fluent
Guardhelpers for common checks - HTTP client base class — typed
HttpClientwith automatic error mapping - OpenAPI + Scalar UI — Swagger docs with interactive API explorer out of the box
- Logging — Serilog-based structured logging
- CORS — configurable cross-origin policy
- Excel/CSV — import and export with column mapping
- Cryptography — AES-256 encrypt/decrypt helpers
- Short IDs — thread-safe random ID generation
Quick Start
dotnet add package Halifax.Api
using Halifax.Api;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHalifax();
var app = builder.Build();
app.UseHalifax();
app.Run("https://*:5000");
This gives you controller routing, exception handling, Swagger, Scalar UI, CORS, and structured logging. Explore the Peggy's Cove sample project for a full working example.
API Responses
All endpoints return a consistent format using ApiResponse:
// Return data
return ApiResponse.With(user);
// Return empty success
return ApiResponse.Empty;
Response format:
{
"data": { ... },
"success": true,
"error": null
}
On error:
{
"data": null,
"success": false,
"error": {
"type": "HalifaxNotFoundException",
"message": "User not found"
}
}
Pagination
[HttpGet]
public ApiResponse<Paging<UserDto>> GetUsers([FromQuery] PagingQuery query)
{
var items = db.Users.Skip(query.Skip).Take(query.Take).ToList();
var total = db.Users.Count();
return ApiResponse.With(new Paging<UserDto>(items, query.Skip, query.Take, total));
}
PagingQuery binds Skip, Take, OrderBy, and OrderDirection from query string parameters.
Exceptions
Throw typed exceptions anywhere in your code — the middleware handles the HTTP response:
| Exception | HTTP Status |
|---|---|
HalifaxException |
400 Bad Request |
HalifaxNotFoundException |
404 Not Found |
HalifaxUnauthorizedException |
401 Unauthorized |
var user = await db.Users.FindAsync(id);
if (user == null)
throw new HalifaxNotFoundException("User not found");
For advanced scenarios, override DefaultExceptionHandler or register your own IExceptionHandler.
Configuration
Halifax loads environment variables from .env files automatically. Define a class or record matching your variable names:
AppSettings__ConnectionString=localhost
AppSettings__HttpTimeout=120
record AppSettings(string ConnectionString, int HttpTimeout);
Register during startup:
builder.Services.AddHalifax(h => h.AddSettings<AppSettings>());
Settings are registered as singletons — inject them into controllers and services, or access them directly:
var settings = Env.GetSection<AppSettings>();
Supported types: string, primitives, DateTime, TimeSpan, Guid, and their nullable variants.
JWT Authentication
Enable authentication with one call:
builder.Services.AddHalifax(h => h
.ConfigureAuthentication("your_jwt_secret_min_16_chars",
validateAudience: false,
validateIssuer: false,
requireExpirationTime: false));
All non-[AllowAnonymous] endpoints now require Authorization: Bearer {token}.
Creating Tokens
var claims = new List<Claim>
{
new("sub", user.Id.ToString()),
new("email", user.Email),
new("role", user.Role)
};
var token = Jwt.Create("your_jwt_secret", claims, DateTime.UtcNow.AddDays(30));
Reading Tokens
var principal = Jwt.Read("your_jwt_secret", token);
Claims-Based Authorization
Create custom authorization filters by extending ClaimsAuthorizeFilterAttribute:
class AdminOnly : ClaimsAuthorizeFilterAttribute
{
protected override bool IsAuthorized(ActionExecutingContext context, List<Claim> claims)
{
claims.ClaimExpected("role", "admin");
return true;
}
}
[HttpGet("admin")]
[AdminOnly]
public ApiResponse GetAdminData() => ApiResponse.With("secret");
Available claim extensions: ClaimExpected, ClaimNotNullOrWhiteSpace, ClaimIsEmail, ClaimIsInt, ClaimIsDouble, ClaimIsEnum<T>, ClaimIsGuid, ClaimIsBoolean.
Validation
Guard provides fluent validation that throws HalifaxException (400) on failure:
Guard.NotNullOrWhiteSpace(request.Name, nameof(request.Name));
Guard.Email(request.Email);
Guard.Length(request.Password, nameof(request.Password), lower: 8, upper: 64);
Guard.Range(request.Age, nameof(request.Age), from: 18, to: 120);
Guard.Url(request.Website, nameof(request.Website));
Guard.Ensure(request.AcceptedTerms, "Terms must be accepted");
Guard.NotNull(request.Address, nameof(request.Address));
Guard.NotEmptyList(request.Tags, nameof(request.Tags));
Guard.Color(request.Theme, nameof(request.Theme));
HTTP Client
Create typed HTTP clients for service-to-service communication by extending HalifaxHttpClient:
public class PaymentClient(HttpClient http) : HalifaxHttpClient(http)
{
public async Task<PaymentDto> GetAsync(string id)
{
var msg = CreateMessage(HttpMethod.Get, $"/api/payments/{id}");
return await SendAsync<PaymentDto>(msg);
}
public async Task<HttpStatusCode> CreateAsync(CreatePaymentRequest request)
{
var msg = CreateMessage(HttpMethod.Post, "/api/payments", request);
return await SendAsync(msg);
}
}
Register with optional defaults:
services.AddHalifaxHttpClient<PaymentClient>(
defaultBaseUrl: "https://payments.api.com",
defaultBearerToken: token);
Error responses (400, 401, 404) from downstream services are automatically mapped to the corresponding Halifax exceptions.
Excel & CSV
dotnet add package Halifax.Excel
var converter = new ExcelConverter<Person>();
converter.AddMapping("Full Name", p => p.Name);
converter.AddMapping("Age", p => p.Age);
// Write
using var stream = new MemoryStream();
await converter.WriteExcelAsync(stream, people, "Sheet1");
await converter.WriteCsvAsync(stream, people);
// Read (auto-detects format from content type)
var records = await converter.ReadAsync(fileStream, contentType);
Utilities
Cryptography
AES-256 encryption:
var encrypted = Crypto.Encrypt("secret", "sensitive data");
var decrypted = Crypto.Decrypt("secret", encrypted);
Crypto.TryDecrypt("secret", encrypted, out var result);
Short IDs
Thread-safe random ID generation:
var id = ShortId.Create(); // e.g. "kX9mBnQ"
var id = ShortId.Create(length: 12); // longer ID
var id = ShortId.Create(useNumbers: false); // letters only
JSON
Pre-configured serialization (camelCase, case-insensitive, enums as strings, UTC dates):
var json = Json.Serialize(obj);
var obj = Json.Deserialize<MyType>(json);
Logging
Global structured logging via Serilog:
L.Info("User created", userId);
L.Warning("Timeout exceeded");
L.Error(exception, "Failed to process");
Full Configuration Example
builder.Services.AddHalifax(h => h
.SetName("My Service")
.AddSettings<AppSettings>()
.AddSettings<DatabaseSettings>()
.ConfigureAuthentication(jwtSecret, false, false, false)
.ConfigureCors(cors => cors
.AllowAnyHeader()
.AllowAnyMethod()
.WithOrigins("https://myapp.com"))
.ConfigureOpenApi(swagger => { /* customize Swashbuckle */ })
.ConfigureJson(opts => { /* customize System.Text.Json */ }));
Package Overview
| Package | Purpose | Dependencies |
|---|---|---|
| Halifax.Domain | Response models, exceptions, pagination | None |
| Halifax.Core | JWT, config, validation, crypto, logging, JSON | Halifax.Domain, Serilog, System.IdentityModel.Tokens.Jwt |
| Halifax.Api | ASP.NET Core integration, middleware, Swagger | Halifax.Core, Swashbuckle, Scalar, JwtBearer |
| Halifax.Http | Typed HttpClient base class | Halifax.Core |
| Halifax.Excel | Excel/CSV import and export | CsvHelper, ExcelMapper, NPOI |
All packages target .NET 10.
MIT License
Copyright (c) 2020 Andrei M
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- Halifax.Core (>= 5.1.0)
- Microsoft.Extensions.Http.Resilience (>= 10.3.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 5.1.1 | 92 | 3/2/2026 |
| 5.1.0 | 82 | 3/2/2026 |
| 5.0.1 | 204 | 1/28/2026 |
| 5.0.0 | 436 | 11/14/2025 |
| 4.0.4 | 233 | 10/4/2025 |
| 4.0.3 | 366 | 9/3/2025 |
| 4.0.2 | 406 | 6/25/2025 |
| 4.0.1 | 496 | 4/6/2025 |
| 4.0.0 | 500 | 11/19/2024 |
| 3.1.4 | 311 | 9/10/2024 |
| 3.1.3 | 503 | 8/7/2024 |
| 3.1.2 | 400 | 5/10/2024 |
| 3.1.1 | 348 | 3/11/2024 |
| 3.1.0 | 317 | 2/11/2024 |
| 3.0.1 | 389 | 1/24/2024 |
| 3.0.0 | 438 | 11/17/2023 |
| 2.0.8 | 248 | 10/30/2023 |
| 2.0.7 | 382 | 9/14/2023 |
| 2.0.6 | 331 | 8/16/2023 |
| 2.0.5 | 359 | 7/9/2023 |
v5.1.1 - Package dependency updates
v5.1.0 - Correlation ID handler, resilience/retry policies, nullable reference types
v5.0.x - .NET 10 support
v4.0.x - .NET 9 support
v3.1.x - Minor improvements to the APIs
v3.0.x - .NET 8 support
v2.0.x - .NET 7 support
v1.0.x - Initial release