Skip to content

Commit c4d0789

Browse files
authored
Merge pull request #3 from TRA-Tech/release/v2
feat: v2.0.0
2 parents 8644578 + 21221ad commit c4d0789

60 files changed

Lines changed: 3117 additions & 880 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
##
44
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
55

6+
# VS Code
7+
.vscode/
8+
69
# User-specific files
710
*.rsuser
811
*.suo

CHANGELOG.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Changelog
2+
3+
All notable changes to this project are documented here.
4+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
5+
6+
---
7+
8+
## [2.0.0] — 2026-04-01
9+
10+
### Breaking Changes
11+
12+
- **Target framework** upgraded from `net8.0` to `net10.0`. Consuming projects must target .NET 10.
13+
- **`Response<T>` removed.** Use `Result<TValue, Error>.ToActionResult()` or `Match` for custom response shapes.
14+
- **`BaseController` removed.** Remove inheritance; use the `ToActionResult()` extension method directly.
15+
- **`GlobalErrorHandlerMiddleware` replaced** by `IExceptionHandler`-based `GlobalExceptionHandler`. Register with `AddExceptionHandler<T>()` and `app.UseExceptionHandler()`.
16+
- **`DbTransactionMiddleware` exception-handler overload removed.** The `Func<IServiceProvider, HttpContext, Exception, Task>` constructor parameter no longer exists. Use `IExceptionHandler` for exception handling.
17+
- **`PagedRequest.CurrentPage` (1-based) renamed to `PageIndex` (0-based).** Aligns with TanStack Table's server-side pagination contract. `Skip` calculation updated accordingly.
18+
- **`StringExtensions` deleted.** Methods used `Convert.*` which has inconsistent null vs invalid-input behavior. Use `int.TryParse`, `decimal.TryParse` etc. directly.
19+
- **`DoubleExtensions` deleted.** `ToInt(this double)` wraps a single `Convert.ToInt32` call with no added value. Use `(int)x` or `Convert.ToInt32(x)` directly.
20+
- **`ObjectExtensions.ToJson()` removed.** Leaked `Newtonsoft.Json` types into caller APIs. Use `System.Text.Json.JsonSerializer.Serialize(obj)` directly.
21+
- **`DateTimeExtensions.DateNow()` removed.** Hardcoded UTC+3 offset makes it unsuitable as a general-purpose utility. Use `TimeZoneInfo.ConvertTime()` explicitly. `IsWeekday()`, `IsWeekend()`, and `ToDateOnly()` are retained.
22+
- **`QueryableExtensions.ToHashSetAsync()` removed.** EF Core 10 provides a native async `ToHashSetAsync()`.
23+
- **`Newtonsoft.Json` package reference removed.** The library now uses `System.Text.Json` exclusively.
24+
25+
### Added
26+
27+
- **`Result<TValue, TError>`** discriminated union with `Match`, `MatchAsync`, `Handle`, `HandleAsync`, `Map`, `Tap`, `Bind`, and `GetValueOrDefault`.
28+
- **`Result<TValue>`** shorthand type (equivalent to `Result<TValue, Error>`) for application code that always uses the library's error hierarchy.
29+
- **Error hierarchy**`abstract record Error` with concrete subtypes: `NotFoundError`, `AlreadyExistsError`, `ConflictError`, `UnauthorizedError`, `ForbiddenError`. Each carries contextual properties via positional constructor and owns its HTTP representation through virtual `StatusCode`, `Detail`, and `Code` properties. Subclass any type to add domain-specific context or override HTTP semantics without modifying library code.
30+
- **`Unit`** struct for void operations (`Result<Unit, Error>`).
31+
- **`ResultExtensions`**`ToActionResult()`, `ToActionResult(int statusCode)`, `ToActionResultAsync()`, and the full async pipeline (`BindAsync`, `Map`, `Tap` Task overloads). Error-to-HTTP mapping reads `StatusCode`, `Detail`, and `Code` directly from the error instance — no switch expression, extensible without library changes.
32+
- **`GlobalExceptionHandler`** — default `IExceptionHandler` implementation that logs unhandled exceptions and returns a 500 ProblemDetails response.
33+
- **`SortColumn`** record — mirrors TanStack Table's `{ id, desc }` sort state shape.
34+
- **`SortedPagedRequest`** — extends `PagedRequest` with `IReadOnlyList<SortColumn> Sorting`. Multi-column sort applied automatically via expression trees + reflection in `ToPagedAsync`.
35+
- **`EnumerableExtensions`**`WhereIf`, `TakeIf`, `SkipIf` for `IEnumerable<T>` (mirrors `QueryableExtensions`).
36+
- **`ConfigurationExtensions.GetRequired`** — returns a config value or throws `InvalidOperationException` when the key is missing. Fills the gap left by `GetRequiredSection` (sections only).
37+
- **`HashExtensions.ToMd5`** — hashes a string to a lowercase MD5 hex string using UTF-8. For non-security use (cache keys, checksums, ETags).
38+
- **`ClaimsPrincipalExtensions`**`GetId<T>`, `GetRequiredId<T>`, `GetEmail`. Uses `IParsable<T>` constraint so callers choose the ID type (`int`, `Guid`, `long`, etc.) without separate overloads.
39+
- **`BrotliHelper`** — static helper with `Compress`/`Decompress` overloads for `byte[]` and `string` (UTF-8 + Base64 for string form).
40+
- **`QueryableExtensions.WhereIf`, `TakeIf`, `SkipIf`** already existed; `ToPagedAsync(SortedPagedRequest)` overload is new.
41+
- **`ApiCommons.Tests`** project — xUnit + FluentAssertions + coverlet test suite covering all phases.
42+
43+
### Changed
44+
45+
- `DbTransactionMiddleware` updated to primary constructor syntax (C# 13).
46+
- `QueryableExtensions.ToPagedAsync` verified compatible with EF Core 10.
47+
- `Microsoft.EntityFrameworkCore` updated from `8.0.22` to `10.0.4`.
48+
49+
### Migration Guide — v1.x → v2.x
50+
51+
| # | What changed | Action required |
52+
|---|---|---|
53+
| 1 | `net8.0` no longer targeted | Upgrade consuming projects to .NET 10 |
54+
| 2 | `BaseController` removed | Remove inheritance; use `ToActionResult()` extension instead |
55+
| 3 | `Response<T>` removed | Use `Result<TValue, Error>.ToActionResult()` or `Match` for custom shapes |
56+
| 4 | `GlobalErrorHandlerMiddleware` replaced | Use `AddGlobalExceptionHandler<T>()` + `UseGlobalErrorHandler()`, or register `IExceptionHandler` manually |
57+
| 5 | `DbTransactionMiddleware` error-handler overload removed | Use `IExceptionHandler` for global exception handling |
58+
| 6 | `PagedRequest.CurrentPage` (1-based) → `PageIndex` (0-based) | Update all usages; aligns with TanStack Table server-side pagination |
59+
| 7 | `ObjectExtensions.ToJson()` removed | Use `JsonSerializer.Serialize(obj)` directly |
60+
| 8 | `DateTimeExtensions.DateNow()` removed | Use `TimeZoneInfo.ConvertTime()` explicitly |
61+
| 9 | `StringExtensions` removed | Use `int.TryParse`, `decimal.TryParse` etc. directly |
62+
| 10 | `DoubleExtensions.ToInt()` removed | Use `(int)x` or `Convert.ToInt32(x)` directly |
63+
| 11 | `QueryableExtensions.ToHashSetAsync()` removed | Use EF Core 10's built-in `.ToHashSetAsync()` |
64+
| 12 | `Newtonsoft.Json` dependency removed | Use `System.Text.Json` exclusively |
65+
66+
**Before / After:**
67+
68+
```csharp
69+
// v1 — error handling
70+
app.UseGlobalErrorHandler(async (sp, ctx, ex) =>
71+
{
72+
ctx.Response.StatusCode = 500;
73+
await ctx.Response.WriteAsync(Response<object>.Fail(...).ToJson());
74+
});
75+
76+
// v2
77+
builder.Services.AddGlobalExceptionHandler<MyExceptionHandler>();
78+
app.UseGlobalErrorHandler();
79+
```
80+
81+
```csharp
82+
// v1 — controller response
83+
Response<string> response = result.Match(s => s, e => string.Empty);
84+
return response.ToActionResult();
85+
86+
// v2
87+
return await _service.GetAsync(id, ct).ToActionResultAsync();
88+
```
89+
90+
```csharp
91+
// v1 — pagination (1-based)
92+
var req = new PagedRequest(currentPage: 1, pageSize: 20);
93+
94+
// v2 — pagination (0-based, aligns with TanStack Table)
95+
var req = new PagedRequest(pageIndex: 0, pageSize: 20);
96+
```
97+
98+
---
99+
100+
## [1.1.0] — prior
101+
102+
- Initial release targeting .NET 8.

0 commit comments

Comments
 (0)