Skip to content

Commit 9d03b87

Browse files
authored
Merge pull request #32 from BenjaminAbt/feature/update-draft-release
2 parents 6dba88a + b33eac5 commit 9d03b87

31 files changed

+593
-221
lines changed

.github/copilot-instructions.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,9 +235,11 @@ Available converters:
235235

236236
## ASP.NET Core Integration
237237

238-
Implement a custom `IModelBinderProvider`:
238+
Implement a custom `IModelBinderProvider` using the `StrongOf.AspNetCore.Mvc` namespace:
239239

240240
```csharp
241+
using StrongOf.AspNetCore.Mvc;
242+
241243
public class StrongOfBinderProvider : IModelBinderProvider
242244
{
243245
private static readonly Dictionary<Type, Type> s_binders = new()
@@ -361,7 +363,10 @@ src/
361363
│ ├── Each concrete type is a single .cs file
362364
│ └── Each file includes the type + its TypeConverter
363365
├── StrongOf.Json/ # JSON converters
364-
├── StrongOf.AspNetCore/ # ASP.NET Core binders
366+
├── StrongOf.AspNetCore/ # ASP.NET Core integration
367+
│ ├── Mvc/ # MVC model binders
368+
│ ├── MinimalApis/ # Minimal API extensions
369+
│ └── OpenApi/ # OpenAPI schema transformer
365370
└── StrongOf.FluentValidation/ # Validation extensions
366371
367372
tests/

.github/release-drafter.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,22 @@ template: |
5252
5353
- `StrongOf`
5454
- `StrongOf.AspNetCore`
55+
- `StrongOf.Json`
5556
- `StrongOf.MemoryCache`
5657
- `StrongOf.Domains`
5758
- `StrongOf.FluentValidation`
59+
- `StrongOf.EntityFrameworkCore`
5860
5961
### Installation
6062
6163
```bash
6264
dotnet add package StrongOf
6365
dotnet add package StrongOf.AspNetCore
66+
dotnet add package StrongOf.Json
6467
dotnet add package StrongOf.MemoryCache
6568
dotnet add package StrongOf.Domains
6669
dotnet add package StrongOf.FluentValidation
70+
dotnet add package StrongOf.EntityFrameworkCore
6771
```
6872
6973
## Contributors

BenjaminAbt.StrongOf.sln

Lines changed: 14 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StrongOf.EntityFrameworkCor
5151
EndProject
5252
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StrongOf.EntityFrameworkCore", "src\StrongOf.EntityFrameworkCore\StrongOf.EntityFrameworkCore.csproj", "{8CAB9635-9405-4817-9072-D8309E07306E}"
5353
EndProject
54-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StrongOf.OpenApi", "src\StrongOf.OpenApi\StrongOf.OpenApi.csproj", "{A3E7B1C2-94D5-4F8E-B6A7-2C1D3E4F5A6B}"
55-
EndProject
56-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StrongOf.MinimalApis", "src\StrongOf.MinimalApis\StrongOf.MinimalApis.csproj", "{C5D6E7F8-1A2B-4C3D-9E8F-7A6B5C4D3E2F}"
54+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StrongOf.AspNetCore.UnitTests", "tests\StrongOf.AspNetCore.UnitTests\StrongOf.AspNetCore.UnitTests.csproj", "{AB938E12-A2DE-4D1E-AC05-3D2CC38C94C7}"
5755
EndProject
5856
Global
5957
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -209,30 +207,18 @@ Global
209207
{8CAB9635-9405-4817-9072-D8309E07306E}.Release|x64.Build.0 = Release|Any CPU
210208
{8CAB9635-9405-4817-9072-D8309E07306E}.Release|x86.ActiveCfg = Release|Any CPU
211209
{8CAB9635-9405-4817-9072-D8309E07306E}.Release|x86.Build.0 = Release|Any CPU
212-
{A3E7B1C2-94D5-4F8E-B6A7-2C1D3E4F5A6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
213-
{A3E7B1C2-94D5-4F8E-B6A7-2C1D3E4F5A6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
214-
{A3E7B1C2-94D5-4F8E-B6A7-2C1D3E4F5A6B}.Debug|x64.ActiveCfg = Debug|Any CPU
215-
{A3E7B1C2-94D5-4F8E-B6A7-2C1D3E4F5A6B}.Debug|x64.Build.0 = Debug|Any CPU
216-
{A3E7B1C2-94D5-4F8E-B6A7-2C1D3E4F5A6B}.Debug|x86.ActiveCfg = Debug|Any CPU
217-
{A3E7B1C2-94D5-4F8E-B6A7-2C1D3E4F5A6B}.Debug|x86.Build.0 = Debug|Any CPU
218-
{A3E7B1C2-94D5-4F8E-B6A7-2C1D3E4F5A6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
219-
{A3E7B1C2-94D5-4F8E-B6A7-2C1D3E4F5A6B}.Release|Any CPU.Build.0 = Release|Any CPU
220-
{A3E7B1C2-94D5-4F8E-B6A7-2C1D3E4F5A6B}.Release|x64.ActiveCfg = Release|Any CPU
221-
{A3E7B1C2-94D5-4F8E-B6A7-2C1D3E4F5A6B}.Release|x64.Build.0 = Release|Any CPU
222-
{A3E7B1C2-94D5-4F8E-B6A7-2C1D3E4F5A6B}.Release|x86.ActiveCfg = Release|Any CPU
223-
{A3E7B1C2-94D5-4F8E-B6A7-2C1D3E4F5A6B}.Release|x86.Build.0 = Release|Any CPU
224-
{C5D6E7F8-1A2B-4C3D-9E8F-7A6B5C4D3E2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
225-
{C5D6E7F8-1A2B-4C3D-9E8F-7A6B5C4D3E2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
226-
{C5D6E7F8-1A2B-4C3D-9E8F-7A6B5C4D3E2F}.Debug|x64.ActiveCfg = Debug|Any CPU
227-
{C5D6E7F8-1A2B-4C3D-9E8F-7A6B5C4D3E2F}.Debug|x64.Build.0 = Debug|Any CPU
228-
{C5D6E7F8-1A2B-4C3D-9E8F-7A6B5C4D3E2F}.Debug|x86.ActiveCfg = Debug|Any CPU
229-
{C5D6E7F8-1A2B-4C3D-9E8F-7A6B5C4D3E2F}.Debug|x86.Build.0 = Debug|Any CPU
230-
{C5D6E7F8-1A2B-4C3D-9E8F-7A6B5C4D3E2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
231-
{C5D6E7F8-1A2B-4C3D-9E8F-7A6B5C4D3E2F}.Release|Any CPU.Build.0 = Release|Any CPU
232-
{C5D6E7F8-1A2B-4C3D-9E8F-7A6B5C4D3E2F}.Release|x64.ActiveCfg = Release|Any CPU
233-
{C5D6E7F8-1A2B-4C3D-9E8F-7A6B5C4D3E2F}.Release|x64.Build.0 = Release|Any CPU
234-
{C5D6E7F8-1A2B-4C3D-9E8F-7A6B5C4D3E2F}.Release|x86.ActiveCfg = Release|Any CPU
235-
{C5D6E7F8-1A2B-4C3D-9E8F-7A6B5C4D3E2F}.Release|x86.Build.0 = Release|Any CPU
210+
{AB938E12-A2DE-4D1E-AC05-3D2CC38C94C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
211+
{AB938E12-A2DE-4D1E-AC05-3D2CC38C94C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
212+
{AB938E12-A2DE-4D1E-AC05-3D2CC38C94C7}.Debug|x64.ActiveCfg = Debug|Any CPU
213+
{AB938E12-A2DE-4D1E-AC05-3D2CC38C94C7}.Debug|x64.Build.0 = Debug|Any CPU
214+
{AB938E12-A2DE-4D1E-AC05-3D2CC38C94C7}.Debug|x86.ActiveCfg = Debug|Any CPU
215+
{AB938E12-A2DE-4D1E-AC05-3D2CC38C94C7}.Debug|x86.Build.0 = Debug|Any CPU
216+
{AB938E12-A2DE-4D1E-AC05-3D2CC38C94C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
217+
{AB938E12-A2DE-4D1E-AC05-3D2CC38C94C7}.Release|Any CPU.Build.0 = Release|Any CPU
218+
{AB938E12-A2DE-4D1E-AC05-3D2CC38C94C7}.Release|x64.ActiveCfg = Release|Any CPU
219+
{AB938E12-A2DE-4D1E-AC05-3D2CC38C94C7}.Release|x64.Build.0 = Release|Any CPU
220+
{AB938E12-A2DE-4D1E-AC05-3D2CC38C94C7}.Release|x86.ActiveCfg = Release|Any CPU
221+
{AB938E12-A2DE-4D1E-AC05-3D2CC38C94C7}.Release|x86.Build.0 = Release|Any CPU
236222
EndGlobalSection
237223
GlobalSection(SolutionProperties) = preSolution
238224
HideSolutionNode = FALSE
@@ -250,8 +236,7 @@ Global
250236
{F739C970-C79D-4F02-9F49-094A02753C92} = {C087DEB7-775E-41AA-A635-7961034570DC}
251237
{12C2E698-E5EF-44A3-B0DC-EAF502FC00C0} = {C087DEB7-775E-41AA-A635-7961034570DC}
252238
{8CAB9635-9405-4817-9072-D8309E07306E} = {C087DEB7-775E-41AA-A635-7961034570DC}
253-
{A3E7B1C2-94D5-4F8E-B6A7-2C1D3E4F5A6B} = {23C114B9-080A-47BC-9FE7-673E1E0B9856}
254-
{C5D6E7F8-1A2B-4C3D-9E8F-7A6B5C4D3E2F} = {23C114B9-080A-47BC-9FE7-673E1E0B9856}
239+
{AB938E12-A2DE-4D1E-AC05-3D2CC38C94C7} = {C087DEB7-775E-41AA-A635-7961034570DC}
255240
EndGlobalSection
256241
GlobalSection(ExtensibilityGlobals) = postSolution
257242
SolutionGuid = {596765F3-28D7-480C-9E4C-03DDD9F0F82C}

README.md

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
[![Build](https://github.com/benjaminabt/StrongOf/actions/workflows/ci.yml/badge.svg)](https://github.com/benjaminabt/StrongOf/actions/workflows/ci.yml)
44

5-
||StrongOf|StrongOf.AspNetCore|StrongOf.Json|StrongOf.FluentValidation|StrongOf.EntityFrameworkCore|StrongOf.OpenApi|
6-
|-|-|-|-|-|-|-|
7-
|*NuGet*|[![NuGet](https://img.shields.io/nuget/v/StrongOf.svg?logo=nuget&label=StrongOf)](https://www.nuget.org/packages/StrongOf/)|[![NuGet](https://img.shields.io/nuget/v/StrongOf.AspNetCore.svg?logo=nuget&label=StrongOf.AspNetCore)](https://www.nuget.org/packages/StrongOf.AspNetCore)|[![NuGet](https://img.shields.io/nuget/v/StrongOf.Json.svg?logo=nuget&label=StrongOf.Json)](https://www.nuget.org/packages/StrongOf.Json)|[![NuGet](https://img.shields.io/nuget/v/StrongOf.FluentValidation.svg?logo=nuget&label=StrongOf.FluentValidation)](https://www.nuget.org/packages/StrongOf.FluentValidation)|[![NuGet](https://img.shields.io/nuget/v/StrongOf.EntityFrameworkCore.svg?logo=nuget&label=StrongOf.EntityFrameworkCore)](https://www.nuget.org/packages/StrongOf.EntityFrameworkCore)|[![NuGet](https://img.shields.io/nuget/v/StrongOf.OpenApi.svg?logo=nuget&label=StrongOf.OpenApi)](https://www.nuget.org/packages/StrongOf.OpenApi)|
5+
||StrongOf|StrongOf.AspNetCore|StrongOf.Json|StrongOf.FluentValidation|StrongOf.EntityFrameworkCore|
6+
|-|-|-|-|-|-|
7+
|*NuGet*|[![NuGet](https://img.shields.io/nuget/v/StrongOf.svg?logo=nuget&label=StrongOf)](https://www.nuget.org/packages/StrongOf/)|[![NuGet](https://img.shields.io/nuget/v/StrongOf.AspNetCore.svg?logo=nuget&label=StrongOf.AspNetCore)](https://www.nuget.org/packages/StrongOf.AspNetCore)|[![NuGet](https://img.shields.io/nuget/v/StrongOf.Json.svg?logo=nuget&label=StrongOf.Json)](https://www.nuget.org/packages/StrongOf.Json)|[![NuGet](https://img.shields.io/nuget/v/StrongOf.FluentValidation.svg?logo=nuget&label=StrongOf.FluentValidation)](https://www.nuget.org/packages/StrongOf.FluentValidation)|[![NuGet](https://img.shields.io/nuget/v/StrongOf.EntityFrameworkCore.svg?logo=nuget&label=StrongOf.EntityFrameworkCore)](https://www.nuget.org/packages/StrongOf.EntityFrameworkCore)|
88

99
All [StrongOf Packages](https://www.nuget.org/packages/StrongOf) are available for .NET 8, .NET 9, .NET 10, and .NET 11.
1010

@@ -163,9 +163,11 @@ string jsonString = JsonSerializer.Serialize(myObject, serializeOptions);
163163

164164
## Usage with ASP.NET Core
165165

166-
You can just use [StrongOf.AspNetCore](https://www.nuget.org/packages/StrongOf.AspNetCore) and use one of the pre-defined binders
166+
You can just use [StrongOf.AspNetCore](https://www.nuget.org/packages/StrongOf.AspNetCore) and use one of the pre-defined binders from the `StrongOf.AspNetCore.Mvc` namespace:
167167

168168
```csharp
169+
using StrongOf.AspNetCore.Mvc;
170+
169171
public class MyBinderProvider : IModelBinderProvider
170172
{
171173
private static readonly IReadOnlyDictionary<Type, Type> s_binders = new Dictionary<Type, Type>
@@ -189,6 +191,8 @@ public class MyBinderProvider : IModelBinderProvider
189191
You can also create a customized binder
190192

191193
```csharp
194+
using StrongOf.AspNetCore.Mvc;
195+
192196
public class MyCustomStrongGuidBinder<TStrong> : StrongOfBinder
193197
where TStrong : StrongGuid<TStrong>
194198
{
@@ -208,6 +212,37 @@ public class MyCustomStrongGuidBinder<TStrong> : StrongOfBinder
208212
}
209213
```
210214

215+
### Usage with Minimal APIs
216+
217+
All strong types implement `IParsable<TSelf>` and work as route/query parameters in Minimal APIs out of the box.
218+
Use the validation filter from `StrongOf.AspNetCore.MinimalApis` to automatically validate `IValidatable` parameters:
219+
220+
```csharp
221+
using StrongOf.AspNetCore.MinimalApis;
222+
223+
// Strong types work as route parameters out of the box
224+
app.MapGet("/users/{id}", (UserId id) => Results.Ok(id));
225+
226+
// Register the endpoint filter for automatic validation of IValidatable types
227+
app.MapPost("/users", (EmailAddress email) => Results.Ok(email))
228+
.WithStrongOfValidation();
229+
```
230+
231+
### Usage with OpenApi (.NET 9+)
232+
233+
Use the schema transformer from `StrongOf.AspNetCore.OpenApi` to correctly map strong types in OpenAPI specs:
234+
235+
```csharp
236+
using StrongOf.AspNetCore.OpenApi;
237+
238+
builder.Services.AddOpenApi(options =>
239+
{
240+
options.AddSchemaTransformer<StrongOfSchemaTransformer>();
241+
});
242+
```
243+
244+
This maps strong types to their underlying primitives (e.g. `UserId` becomes `string (uuid)` instead of a complex object).
245+
211246
## Usage with Entity Framework Core
212247

213248
Install [StrongOf.EntityFrameworkCore](https://www.nuget.org/packages/StrongOf.EntityFrameworkCore) for first-class EF Core integration with a generic value converter that works for all strong types - no per-type converter classes needed.

src/StrongOf.MinimalApis/StrongOfEndpointExtensions.cs renamed to src/StrongOf.AspNetCore/MinimalApis/StrongOfEndpointExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
using Microsoft.AspNetCore.Builder;
44
using Microsoft.AspNetCore.Http;
55

6-
namespace StrongOf.MinimalApis;
6+
namespace StrongOf.AspNetCore.MinimalApis;
77

88
/// <summary>
99
/// Provides extension methods for configuring StrongOf validation on Minimal API endpoints.

src/StrongOf.MinimalApis/StrongOfValidationFilter.cs renamed to src/StrongOf.AspNetCore/MinimalApis/StrongOfValidationFilter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
using Microsoft.AspNetCore.Http;
44

5-
namespace StrongOf.MinimalApis;
5+
namespace StrongOf.AspNetCore.MinimalApis;
66

77
/// <summary>
88
/// An endpoint filter that validates <see cref="IValidatable"/> strong type parameters

src/StrongOf.AspNetCore/StrongBooleanBinder.cs renamed to src/StrongOf.AspNetCore/Mvc/StrongBooleanBinder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
using Microsoft.AspNetCore.Mvc.ModelBinding;
44

5-
namespace StrongOf.AspNetCore;
5+
namespace StrongOf.AspNetCore.Mvc;
66

77
/// <summary>
88
/// Represents a binder for StrongBoolean type.

src/StrongOf.AspNetCore/StrongCharBinder.cs renamed to src/StrongOf.AspNetCore/Mvc/StrongCharBinder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
// Copyright © Benjamin Abt (https://benjamin-abt.com) - all rights reserved
1+
// Copyright © Benjamin Abt (https://benjamin-abt.com) - all rights reserved
22

33
using Microsoft.AspNetCore.Mvc.ModelBinding;
44

5-
namespace StrongOf.AspNetCore;
5+
namespace StrongOf.AspNetCore.Mvc;
66

77
/// <summary>
88
/// Represents a binder for StrongChar type.

src/StrongOf.AspNetCore/StrongDateTimeBinder.cs renamed to src/StrongOf.AspNetCore/Mvc/StrongDateTimeBinder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
// Copyright © Benjamin Abt (https://benjamin-abt.com) - all rights reserved
1+
// Copyright © Benjamin Abt (https://benjamin-abt.com) - all rights reserved
22

33
using Microsoft.AspNetCore.Mvc.ModelBinding;
44

5-
namespace StrongOf.AspNetCore;
5+
namespace StrongOf.AspNetCore.Mvc;
66

77
/// <summary>
88
/// Represents a binder for StrongDateTime type.

src/StrongOf.AspNetCore/StrongDateTimeOffsetBinder.cs renamed to src/StrongOf.AspNetCore/Mvc/StrongDateTimeOffsetBinder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
// Copyright © Benjamin Abt (https://benjamin-abt.com) - all rights reserved
1+
// Copyright © Benjamin Abt (https://benjamin-abt.com) - all rights reserved
22

33
using Microsoft.AspNetCore.Mvc.ModelBinding;
44

5-
namespace StrongOf.AspNetCore;
5+
namespace StrongOf.AspNetCore.Mvc;
66

77
/// <summary>
88
/// Represents a binder for StrongDateTimeOffset type.

0 commit comments

Comments
 (0)