Skip to content

Commit 2ee46ac

Browse files
authored
refactor: .NET 10 update (#355)
* chore: update project SDKs and target frameworks; remove obsolete Windows-specific converters - Changed global.json to use new SDK versioning format. - Updated Directory.Build.props to enable nullable reference types and continuous integration build settings. - Refactored MADE.Collections project to target net8.0 and net10.0, switching to Microsoft.NET.Sdk. - Deleted obsolete Windows-specific BooleanToStringValueConverter and DateTimeToStringValueConverter files. - Updated MADE.Data.Converters to target net8.0 and net10.0, refactoring converters to remove partial class definitions. - Updated MADE.Data.EFCore project to target net8.0 and net10.0, updating package references for EF Core. - Updated all MADE.* projects to use Microsoft.NET.Sdk and target net8.0 and net10.0. - Updated test projects to target net8.0 and net10.0, updating package references to latest versions. * feat: migrate to System.Text.Json and drop third-party dependencies Replace Newtonsoft.Json with System.Text.Json across Networking, Web, Web.Mvc, and Data.Serialization libraries. Replace JsonTypeMigrationSerializationBinder with JsonTypeMigrationConverter using System.Text.Json's JsonConverter API. Remove Z.EntityFramework.Plus.EFCore from Data.EFCore, reimplementing OrderBy using expression trees. Add QueryableExtensions tests for OrderBy and Page. Add CHANGELOG.md documenting all v3 breaking changes with migration guidance. * refactor: modernize codebase with file-scoped namespaces, nullable annotations, and async improvements - Convert all source and test files to file-scoped namespace declarations - Add ConfigureAwait(false) to all 52 await expressions in library code - Replace manual null checks with ArgumentNullException.ThrowIfNull (22 locations) - Add nullable reference type annotations to public APIs (13 fixes across 11 files) - Change IEventLogger methods from void to Task for proper async support - Simplify JsonTypeMigrationConverter: rename AddTypeMigrationAsync to AddTypeMigration, replace SemaphoreSlim with lock - Fix flaky EntityBaseTests by capturing timestamps around save operations - Add comprehensive .editorconfig with modern .NET analysis rules - Update CHANGELOG.md with v3 breaking changes and QOL improvements * refactor: add nullable annotations to improve code safety and clarity * refactor: enhance nullability annotations and improve code safety across multiple files * refactor: enhance nullability annotations and improve code safety across multiple files * docs: enhance documentation and features across multiple articles - Updated threading.md to include ITimer interface and TaskExtensions for better async task handling. - Added JsonResult for returning JSON with custom status codes in web-mvc.md. - Introduced AuthenticatedUser and API versioning support in web.md. - Revised intro.md to reflect updated target frameworks and added new features in various packages. - Removed obsolete Media Image section from the table of contents. - Updated docfx.json to target net10.0 and modified templates for a modern look. - Created a new custom CSS file for improved styling on the landing page. - Deleted outdated material template files to streamline the documentation structure. - Adjusted table of contents to point to articles instead of docs. * feat: add assertion helpers, async primitives, and EFCore extensions New features across multiple packages: - Testing: assertion extensions for objects, booleans, comparables, strings, and exceptions (ShouldBeNull, ShouldBeTrue, ShouldThrow, etc.) - Threading: AsyncLazy<T>, Debouncer, and Throttler - Data.EFCore: soft-delete (ISoftDeletable) and audit trail (IAuditableEntity) with DbContext extensions - Data.Validation: IAsyncValidator and AsyncValidatorCollection - Networking: MultipartFormDataPostNetworkRequest and RetryDelegatingHandler with exponential backoff - Web.Mvc: ForbiddenObjectResult (403) with controller extensions Also adds CancellationToken support to async methods that were missing it, and updates documentation for all new and existing features. * feat: add value converters and extensions for DateTime, string, and file size; enhance length and math conversions * test: add tests for new features across all packages * fix(tests): use mock handler for error tests, keep real service for success The httpbin.org error tests were flaky in CI because the external service can return transient errors (502) instead of the expected status code (405). Success tests still hit httpbin.org to prove real HTTP plumbing works. Error tests now use a MockHttpMessageHandler for deterministic assertions. * feat(networking): add INetworkRequestFactory for DI-friendly request creation Wraps IHttpClientFactory to eliminate manual HttpClient management. Supports named clients via WithClient() and one-line DI registration with services.AddNetworkRequestFactory(). Documentation updated to use the factory as the primary recommended approach.
1 parent 53611a4 commit 2ee46ac

274 files changed

Lines changed: 16754 additions & 13194 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.

.editorconfig

Lines changed: 114 additions & 123 deletions
Large diffs are not rendered by default.

.github/dependabot.yml

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,42 @@
11
version: 2
22
updates:
3-
- package-ecosystem: nuget
4-
directory: "/"
5-
schedule:
6-
interval: daily
7-
open-pull-requests-limit: 10
3+
- package-ecosystem: nuget
4+
directory: "/"
5+
schedule:
6+
interval: weekly
7+
day: monday
8+
open-pull-requests-limit: 10
9+
commit-message:
10+
prefix: "chore"
11+
include: "scope"
12+
groups:
13+
testing:
14+
patterns:
15+
- "coverlet*"
16+
- "Microsoft.NET.Test*"
17+
- "NUnit*"
18+
- "Shouldly"
19+
- "Bogus"
20+
- "Moq"
21+
entity-framework:
22+
patterns:
23+
- "Microsoft.EntityFrameworkCore*"
24+
aspnet:
25+
patterns:
26+
- "Asp.Versioning*"
27+
analyzers:
28+
patterns:
29+
- "Microsoft.SourceLink*"
30+
validation:
31+
patterns:
32+
- "FluentValidation*"
33+
34+
- package-ecosystem: github-actions
35+
directory: "/"
36+
schedule:
37+
interval: weekly
38+
day: monday
39+
open-pull-requests-limit: 5
40+
commit-message:
41+
prefix: "ci"
42+
include: "scope"

.github/workflows/ci.yml

Lines changed: 83 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,39 @@ on:
88
- main
99
paths:
1010
- src/**
11-
- samples/**
1211
- tests/**
1312
- build/**
1413
- .github/workflows/ci.yml
14+
- Directory.Build.props
1515
- global.json
1616
pull_request:
1717
branches:
1818
- main
1919
paths:
2020
- src/**
21-
- samples/**
2221
- tests/**
2322
- build/**
2423
- .github/workflows/ci.yml
24+
- Directory.Build.props
2525
- global.json
2626
workflow_dispatch:
2727

28+
permissions:
29+
contents: read
30+
pull-requests: write
31+
2832
jobs:
29-
build:
33+
build-test:
34+
runs-on: ubuntu-latest
3035

3136
env:
3237
BUILD_CONFIG: 'Release'
3338
SOLUTION: 'MADE.NET.sln'
3439

35-
runs-on: windows-latest
36-
3740
steps:
38-
- uses: actions/checkout@v2
41+
- uses: actions/checkout@v6
42+
with:
43+
fetch-depth: 0
3944

4045
- name: Get Build Version
4146
run: |
@@ -45,33 +50,88 @@ jobs:
4550
echo "BUILD_VERSION=$version" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
4651
shell: pwsh
4752

48-
- name: Setup .NET 6.0
49-
uses: actions/setup-dotnet@v1
53+
- name: Setup .NET 8.0
54+
uses: actions/setup-dotnet@v5
55+
with:
56+
dotnet-version: 8.0.x
57+
58+
- name: Setup .NET 10.0
59+
uses: actions/setup-dotnet@v5
5060
with:
51-
dotnet-version: 6.0.x
61+
dotnet-version: 10.0.3xx
62+
63+
- name: Restore dependencies
64+
run: dotnet restore $SOLUTION
5265

53-
- name: Setup .NET 7.0
54-
uses: actions/setup-dotnet@v1
66+
- name: Build
67+
run: dotnet build $SOLUTION --configuration $BUILD_CONFIG --no-restore -p:Version=$BUILD_VERSION
68+
69+
- name: Run tests
70+
run: >
71+
dotnet test
72+
--configuration $BUILD_CONFIG
73+
--no-restore
74+
--no-build
75+
--collect:"XPlat Code Coverage"
76+
77+
- name: Generate coverage report
78+
uses: danielpalme/ReportGenerator-GitHub-Action@5
5579
with:
56-
dotnet-version: 7.0.x
80+
reports: '**/coverage.cobertura.xml'
81+
targetdir: 'coverage-report'
82+
reporttypes: 'MarkdownSummaryGithub;Cobertura'
83+
84+
- name: Publish coverage to workflow summary
85+
run: cat coverage-report/SummaryGithub.md >> $GITHUB_STEP_SUMMARY
86+
87+
- name: Post coverage to PR
88+
if: github.event_name == 'pull_request'
89+
run: gh pr comment $PR_NUMBER --edit-last --create-if-none --body-file coverage-report/SummaryGithub.md
90+
env:
91+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
92+
PR_NUMBER: ${{ github.event.number }}
93+
94+
publish:
95+
needs: build-test
96+
if: startsWith(github.ref, 'refs/tags/v')
97+
runs-on: ubuntu-latest
98+
99+
env:
100+
BUILD_CONFIG: 'Release'
101+
SOLUTION: 'MADE.NET.sln'
102+
103+
steps:
104+
- uses: actions/checkout@v6
105+
with:
106+
fetch-depth: 0
107+
108+
- name: Get Build Version
109+
run: |
110+
Import-Module .\build\GetBuildVersion.psm1
111+
Write-Host $Env:GITHUB_REF
112+
$version = GetBuildVersion -VersionString $Env:GITHUB_REF
113+
echo "BUILD_VERSION=$version" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
114+
shell: pwsh
57115

58116
- name: Setup .NET 8.0
59-
uses: actions/setup-dotnet@v1
117+
uses: actions/setup-dotnet@v5
60118
with:
61119
dotnet-version: 8.0.x
62120

121+
- name: Setup .NET 10.0
122+
uses: actions/setup-dotnet@v5
123+
with:
124+
dotnet-version: 10.0.3xx
125+
63126
- name: Restore dependencies
64127
run: dotnet restore $SOLUTION
65128

66-
- name: Setup MSBuild
67-
uses: microsoft/setup-msbuild@v1.0.2
68-
69129
- name: Build
70-
run: msbuild $env:SOLUTION /p:Configuration=$env:BUILD_CONFIG /p:Platform="Any CPU" -p:Version=$env:BUILD_VERSION
130+
run: dotnet build $SOLUTION --configuration $BUILD_CONFIG --no-restore -p:Version=$BUILD_VERSION
71131

72-
- name: Run tests
73-
run: dotnet test /p:Configuration=$env:BUILD_CONFIG /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura --no-restore --no-build --verbosity normal
74-
75-
- name: Publish
76-
if: startsWith(github.ref, 'refs/tags/v')
77-
run: nuget push **\*.nupkg -Source 'https://api.nuget.org/v3/index.json' -ApiKey ${{secrets.NUGET_API_KEY}}
132+
- name: Publish to NuGet.org
133+
run: |
134+
Get-ChildItem . -Recurse -Filter *.nupkg | ForEach-Object {
135+
dotnet nuget push $_.FullName --source 'https://api.nuget.org/v3/index.json' --api-key '${{ secrets.NUGET_API_KEY }}' --skip-duplicate
136+
}
137+
shell: pwsh

.github/workflows/docs.yml

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,50 +16,41 @@ on:
1616
- .github/workflows/docs.yml
1717
workflow_dispatch:
1818

19+
permissions:
20+
contents: write
21+
1922
jobs:
2023
generate-docs:
2124

22-
runs-on: windows-latest
25+
runs-on: ubuntu-latest
2326

2427
steps:
25-
- uses: actions/checkout@v2
26-
27-
- name: Setup .NET 6.0
28-
uses: actions/setup-dotnet@v1
29-
with:
30-
dotnet-version: 6.0.x
31-
32-
- name: Setup .NET 7.0
33-
uses: actions/setup-dotnet@v1
34-
with:
35-
dotnet-version: 7.0.x
28+
- uses: actions/checkout@v6
3629

3730
- name: Setup .NET 8.0
38-
uses: actions/setup-dotnet@v1
31+
uses: actions/setup-dotnet@v5
3932
with:
4033
dotnet-version: 8.0.x
4134

42-
- name: Setup MSBuild
43-
uses: microsoft/setup-msbuild@v1.0.2
44-
45-
- name: Setup DocFX
46-
uses: crazy-max/ghaction-chocolatey@v1
35+
- name: Setup .NET 10.0
36+
uses: actions/setup-dotnet@v5
4737
with:
48-
args: install docfx
38+
dotnet-version: 10.0.3xx
4939

50-
- name: Generate DocFX metadata
51-
working-directory: docs
52-
run: docfx metadata .\docfx.json
53-
continue-on-error: false
40+
- name: Install DocFX
41+
run: dotnet tool install -g docfx
42+
43+
- name: Restore projects
44+
run: dotnet restore MADE.NET.sln
5445

5546
- name: Build DocFX site
5647
working-directory: docs
57-
run: docfx .\docfx.json
48+
run: docfx docfx.json
5849
continue-on-error: false
5950

6051
- name: Publish DocFX site
6152
if: github.event_name == 'push'
62-
uses: peaceiris/actions-gh-pages@v3
53+
uses: peaceiris/actions-gh-pages@v4
6354
with:
6455
github_token: ${{ secrets.GITHUB_TOKEN }}
6556
publish_dir: docs/_site

CHANGELOG.md

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# Changelog
2+
3+
## v3.0.0
4+
5+
### Breaking Changes
6+
7+
#### Target Framework Updates
8+
9+
- All libraries now target `net8.0` and `net10.0`. Previous target frameworks have been removed.
10+
11+
#### Newtonsoft.Json Replaced with System.Text.Json
12+
13+
The following libraries have migrated from `Newtonsoft.Json` to `System.Text.Json`. All public APIs that previously accepted `Newtonsoft.Json.JsonSerializerSettings` now accept `System.Text.Json.JsonSerializerOptions`.
14+
15+
**MADE.Web.Mvc**
16+
17+
- `JsonResult` constructor parameter type changed from `JsonSerializerSettings` to `JsonSerializerOptions`.
18+
- `JsonResult.SerializerOptions` property type changed from `JsonSerializerSettings` to `JsonSerializerOptions`.
19+
- `ControllerBaseExtensions.Json()` parameter type changed from `JsonSerializerSettings` to `JsonSerializerOptions`.
20+
21+
**MADE.Web**
22+
23+
- All `HttpResponseExtensions.WriteJsonAsync()` overloads that accepted `JsonSerializerSettings` now accept `JsonSerializerOptions`.
24+
25+
**MADE.Networking**
26+
27+
- Internal serialization switched from `Newtonsoft.Json` to `System.Text.Json`. All deserialization uses `PropertyNameCaseInsensitive = true` to maintain behavioral compatibility.
28+
- No public API signature changes.
29+
30+
**MADE.Data.Serialization**
31+
32+
- `JsonTypeMigrationSerializationBinder` has been removed. Use `JsonTypeMigrationConverter` instead (see migration guide below).
33+
34+
### Removed Dependencies
35+
36+
| Library | Removed Dependency | Replacement |
37+
| --- | --- | --- |
38+
| MADE.Networking | `Newtonsoft.Json` | `System.Text.Json` (built-in) |
39+
| MADE.Web | `Newtonsoft.Json` | `System.Text.Json` (built-in) |
40+
| MADE.Web.Mvc | `Newtonsoft.Json` | `System.Text.Json` (built-in) |
41+
| MADE.Data.Serialization | `Newtonsoft.Json` | `System.Text.Json` (built-in) |
42+
| MADE.Data.EFCore | `Z.EntityFramework.Plus.EFCore` | Custom implementation using Expression trees |
43+
44+
### Migration Guide
45+
46+
#### Newtonsoft.Json to System.Text.Json
47+
48+
Replace `using Newtonsoft.Json` with `using System.Text.Json` and update any `JsonSerializerSettings` references to `JsonSerializerOptions`.
49+
50+
```csharp
51+
// Before (v2)
52+
using Newtonsoft.Json;
53+
54+
var result = controller.Json(value, HttpStatusCode.OK, new JsonSerializerSettings
55+
{
56+
NullValueHandling = NullValueHandling.Ignore
57+
});
58+
59+
// After (v3)
60+
using System.Text.Json;
61+
62+
var result = controller.Json(value, HttpStatusCode.OK, new JsonSerializerOptions
63+
{
64+
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
65+
});
66+
```
67+
68+
#### JsonTypeMigrationSerializationBinder to JsonTypeMigrationConverter
69+
70+
The Newtonsoft.Json-based `JsonTypeMigrationSerializationBinder` in the `MADE.Data.Serialization.Json.Binders` namespace has been replaced with `JsonTypeMigrationConverter` in the `MADE.Data.Serialization.Json.Converters` namespace.
71+
72+
```csharp
73+
// Before (v2)
74+
using MADE.Data.Serialization.Json.Binders;
75+
76+
var binder = new JsonTypeMigrationSerializationBinder();
77+
binder.AddTypeMigration(new JsonTypeMigration("OldAssembly", "OldNamespace.OldType", typeof(NewType)));
78+
79+
var settings = new JsonSerializerSettings
80+
{
81+
TypeNameHandling = TypeNameHandling.All,
82+
SerializationBinder = binder
83+
};
84+
var result = JsonConvert.DeserializeObject<object>(json, settings);
85+
86+
// After (v3)
87+
using MADE.Data.Serialization.Json.Converters;
88+
89+
var converter = new JsonTypeMigrationConverter();
90+
converter.AddTypeMigration(new JsonTypeMigration("OldAssembly", "OldNamespace.OldType", typeof(NewType)));
91+
92+
var options = new JsonSerializerOptions();
93+
options.Converters.Add(converter);
94+
var result = JsonSerializer.Deserialize<object>(json, options);
95+
```
96+
97+
#### IEventLogger Methods Changed from void to Task
98+
99+
All 15 methods on `IEventLogger` (`WriteDebug`, `WriteInfo`, `WriteWarning`, `WriteError`, `WriteCritical` and their overloads) now return `Task` instead of `void`. Implementations must be updated accordingly.
100+
101+
#### JsonTypeMigrationConverter Simplified
102+
103+
- `AddTypeMigrationAsync` has been renamed to `AddTypeMigration` and is now synchronous (uses `lock` instead of `SemaphoreSlim`).
104+
105+
### Code Quality Improvements
106+
107+
- **File-scoped namespaces**: All source files converted to file-scoped namespace declarations.
108+
- **ConfigureAwait(false)**: Added to all `await` expressions in library code (52 locations across 17 files) to prevent deadlocks in synchronization-context-bound environments.
109+
- **ArgumentNullException.ThrowIfNull**: Replaced manual null-check-and-throw patterns with `ArgumentNullException.ThrowIfNull()` (22 locations across 7 files).
110+
- **Nullable reference type annotations**: Added `?` annotations to parameters, return types, fields, and properties that accept or return `null` (17 fixes across 10 files).
111+
- **Async correctness**: `FileEventLogger` and `AppDiagnostics` rewritten for proper async patterns, removing `async void` methods.
112+
- **Comprehensive .editorconfig**: Added modern .NET analysis rules including CA2007, CA1822, CA1849, and async naming conventions.

0 commit comments

Comments
 (0)