Skip to content

Commit f732347

Browse files
v1.0.0 (#1)
* Initial version
1 parent 99b9df2 commit f732347

23 files changed

+832
-1
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Continuous Integration
2+
3+
on:
4+
pull_request:
5+
branches: [ "main" ]
6+
push:
7+
branches: [ "releases/**" ]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v3
14+
15+
- name: Setup .NET 6.x
16+
uses: actions/setup-dotnet@v3
17+
with:
18+
dotnet-version: '6.x'
19+
20+
- name: Build
21+
run: dotnet build --property:Configuration=Debug "PosInformatique.FluentValidation.Json.sln"
22+
23+
- name: Test with the dotnet CLI
24+
run: dotnet test --property:Configuration=Debug "PosInformatique.FluentValidation.Json.sln"
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Release
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
VersionPrefix:
7+
type: string
8+
description: The version of the library
9+
required: true
10+
default: 1.0.0
11+
VersionSuffix:
12+
type: string
13+
description: The version suffix of the library (for example rc.1)
14+
15+
run-name: ${{ inputs.VersionPrefix }}-${{ inputs.VersionSuffix }}
16+
17+
jobs:
18+
build:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v3
22+
23+
- name: Setup .NET 6.x
24+
uses: actions/setup-dotnet@v3
25+
with:
26+
dotnet-version: '6.x'
27+
28+
- name: Build
29+
run: dotnet pack
30+
--property:Configuration=Release
31+
--property:VersionPrefix=${{ github.event.inputs.VersionPrefix }}
32+
--property:VersionSuffix=${{ github.event.inputs.VersionSuffix }}
33+
"src/FluentValidation.Json/FluentValidation.Json.csproj"
34+
35+
- name: Publish the package to nuget.org
36+
run: dotnet nuget push "src/FluentValidation.Json/bin/Release/*.nupkg" --api-key "${{ secrets.NUGET_APIKEY }}" --source https://api.nuget.org/v3/index.json

Directory.Build.props

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<Project>
2+
3+
<!-- Common properties -->
4+
<PropertyGroup>
5+
<Authors>Gilles TOURREAU</Authors>
6+
<Company>P.O.S Informatique</Company>
7+
<Product>P.O.S Informatique</Product>
8+
<Copyright>Copyright (c) P.O.S Informatique. All rights reserved.</Copyright>
9+
<RepositoryUrl>https://github.com/PosInformatique/PosInformatique.FluentValidation.Json</RepositoryUrl>
10+
<RepositoryType>git</RepositoryType>
11+
12+
<!-- Enable the last version of C# -->
13+
<LangVersion>latest</LangVersion>
14+
15+
<!-- Enable implict usings -->
16+
<ImplicitUsings>enable</ImplicitUsings>
17+
18+
<!-- Disable the Analyzers in Release configuration -->
19+
<RunAnalyzers Condition="'$(Configuration)' == 'Release'">false</RunAnalyzers>
20+
21+
<!-- Disable the StyleCop 'XML comment analysis is disabled due to project configuration' warning. -->
22+
<NoWarn>$(NoWarn);SA0001</NoWarn>
23+
24+
<!-- By default prefix all the assemblies name with ChantierConnect -->
25+
<AssemblyName>PosInformatique.$(MSBuildProjectName)</AssemblyName>
26+
<RootNamespace>PosInformatique.$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace>
27+
</PropertyGroup>
28+
29+
<ItemGroup>
30+
<AdditionalFiles Include="..\..\stylecop.json">
31+
<Link>stylecop.json</Link>
32+
</AdditionalFiles>
33+
</ItemGroup>
34+
35+
<ItemGroup>
36+
<None Include="..\..\.editorconfig" Link=".editorconfig" />
37+
</ItemGroup>
38+
39+
<!-- Common NuGet packages -->
40+
<ItemGroup>
41+
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556">
42+
<PrivateAssets>all</PrivateAssets>
43+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
44+
</PackageReference>
45+
</ItemGroup>
46+
47+
<!-- Add the default using directive for all the code -->
48+
<ItemGroup>
49+
<Using Include="System" />
50+
</ItemGroup>
51+
52+
</Project>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.8.34322.80
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FluentValidation.Json", "src\FluentValidation.Json\FluentValidation.Json.csproj", "{167212EF-5D0C-4337-B194-AAD7ED65E1E8}"
7+
EndProject
8+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A43FECF3-4814-4A46-9BF3-3D2DB1AE8C9C}"
9+
ProjectSection(SolutionItems) = preProject
10+
.gitignore = .gitignore
11+
Directory.Build.props = Directory.Build.props
12+
LICENSE = LICENSE
13+
README.md = README.md
14+
stylecop.json = stylecop.json
15+
EndProjectSection
16+
EndProject
17+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FluentValidation.Json.Tests", "tests\FluentValidation.Json.Tests\FluentValidation.Json.Tests.csproj", "{353E2153-FCBF-4075-BB65-B2B112271E72}"
18+
EndProject
19+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{1A79F106-1CB8-44EA-A384-BFC3409B7B60}"
20+
ProjectSection(SolutionItems) = preProject
21+
tests\.editorconfig = tests\.editorconfig
22+
EndProjectSection
23+
EndProject
24+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{36D08C64-14B2-4956-9F31-4AEB42856954}"
25+
EndProject
26+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{F25D728E-67C8-45EC-9B72-150324BEE428}"
27+
ProjectSection(SolutionItems) = preProject
28+
.github\workflows\github-actions-ci.yaml = .github\workflows\github-actions-ci.yaml
29+
.github\workflows\github-actions-release.yml = .github\workflows\github-actions-release.yml
30+
EndProjectSection
31+
EndProject
32+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentValidation.Json.AspNetCore.Tests", "tests\FluentValidation.Json.AspNetCore.Tests\FluentValidation.Json.AspNetCore.Tests.csproj", "{63584847-032C-4BDA-A2E1-AE20C27B784E}"
33+
EndProject
34+
Global
35+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
36+
Debug|Any CPU = Debug|Any CPU
37+
Release|Any CPU = Release|Any CPU
38+
EndGlobalSection
39+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
40+
{167212EF-5D0C-4337-B194-AAD7ED65E1E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41+
{167212EF-5D0C-4337-B194-AAD7ED65E1E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
42+
{167212EF-5D0C-4337-B194-AAD7ED65E1E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
43+
{167212EF-5D0C-4337-B194-AAD7ED65E1E8}.Release|Any CPU.Build.0 = Release|Any CPU
44+
{353E2153-FCBF-4075-BB65-B2B112271E72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45+
{353E2153-FCBF-4075-BB65-B2B112271E72}.Debug|Any CPU.Build.0 = Debug|Any CPU
46+
{353E2153-FCBF-4075-BB65-B2B112271E72}.Release|Any CPU.ActiveCfg = Release|Any CPU
47+
{353E2153-FCBF-4075-BB65-B2B112271E72}.Release|Any CPU.Build.0 = Release|Any CPU
48+
{63584847-032C-4BDA-A2E1-AE20C27B784E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
49+
{63584847-032C-4BDA-A2E1-AE20C27B784E}.Debug|Any CPU.Build.0 = Debug|Any CPU
50+
{63584847-032C-4BDA-A2E1-AE20C27B784E}.Release|Any CPU.ActiveCfg = Release|Any CPU
51+
{63584847-032C-4BDA-A2E1-AE20C27B784E}.Release|Any CPU.Build.0 = Release|Any CPU
52+
EndGlobalSection
53+
GlobalSection(SolutionProperties) = preSolution
54+
HideSolutionNode = FALSE
55+
EndGlobalSection
56+
GlobalSection(NestedProjects) = preSolution
57+
{1A79F106-1CB8-44EA-A384-BFC3409B7B60} = {A43FECF3-4814-4A46-9BF3-3D2DB1AE8C9C}
58+
{36D08C64-14B2-4956-9F31-4AEB42856954} = {A43FECF3-4814-4A46-9BF3-3D2DB1AE8C9C}
59+
{F25D728E-67C8-45EC-9B72-150324BEE428} = {36D08C64-14B2-4956-9F31-4AEB42856954}
60+
EndGlobalSection
61+
GlobalSection(ExtensibilityGlobals) = postSolution
62+
SolutionGuid = {05F51EFD-F92A-41C6-9A20-E3F7E6C7829E}
63+
EndGlobalSection
64+
EndGlobal

README.md

Lines changed: 205 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,206 @@
11
# PosInformatique.FluentValidation.Json
2-
PosInformatique.FluentValidation.Json is a library based on FluentValidation to validate JSON object for the Web API.
2+
[PosInformatique.FluentValidation.Json](https://www.nuget.org/packages/PosInformatique.FluentValidation.Json/)
3+
is a library based on FluentValidation to validate JSON objects for the Web API.
4+
5+
By default, when using the [FluentValidation](https://www.nuget.org/packages/FluentValidation)
6+
library to validate an object, the property name (or related display name) are used in the error message.
7+
This can be useful for functional validation to display to users on the views of the application.
8+
9+
But when you perform some validations in a Web API context, on JSON DTO objects,
10+
using C# property name does not help developers to indicate which properties are invalid.
11+
Specially if the C# property name is differents of the JSON property name associated.
12+
13+
For example, imagine you have the following JSON object that represents a product:
14+
15+
```json
16+
{
17+
"description": "Chicken adobo",
18+
"price": 10
19+
}
20+
```
21+
22+
This JSON object is mapped to the following C# class, using `[JsonPropertyName]` attributes
23+
to define the JSON property names.
24+
25+
```csharp
26+
public class Product
27+
{
28+
public Product()
29+
{
30+
}
31+
32+
[JsonPropertyName("category")]
33+
public ProductCategory? Category { get; set; }
34+
35+
[JsonPropertyName("description")]
36+
public string? Description { get; set; }
37+
38+
[JsonPropertyName("price")]
39+
public decimal Price { get; set; }
40+
}
41+
```
42+
43+
If you want to validate the C# `Product` class, you have to create a validator
44+
which inherit from the `AbstractValidator<T>` class.
45+
46+
```csharp
47+
public class ProductValidator : AbstractValidator<Product>
48+
{
49+
public ProductValidator()
50+
{
51+
this.RuleLevelCascadeMode = CascadeMode.Stop;
52+
53+
this.RuleFor(p => p.Description).NotNull().NotEmpty();
54+
this.RuleFor(p => p.Price).GreaterThan(0);
55+
this.RuleFor(p => p.Category).NotNull().SetValidator(new ProductCategoryValidator());
56+
}
57+
}
58+
59+
public class ProductCategoryValidator : AbstractValidator<ProductCategory>
60+
{
61+
public ProductCategoryValidator()
62+
{
63+
this.RuleFor(p => p.Name).NotEmpty();
64+
}
65+
}
66+
```
67+
68+
When performing the validation of inside a ASP .NET MVC API application
69+
the following JSON problem is returned by default:
70+
71+
```json
72+
{
73+
"value": {
74+
"title": "One or more validation errors occurred.",
75+
"errors": {
76+
"Description": [
77+
"'Description' must not be empty."
78+
],
79+
"Price": [
80+
"'Price' must be greater than '0'."
81+
],
82+
"Category.Name": [
83+
"'Name' must not be empty."
84+
]
85+
}
86+
},
87+
"statusCode": 400,
88+
"contentType": "application/problem+json"
89+
}
90+
```
91+
92+
Here, because we expose this JSON content to developers, we preferred to
93+
have the JSON property name path in the errors messages.
94+
95+
This the main goal of this library to return the following JSON result instead:
96+
97+
```json
98+
{
99+
"value": {
100+
"title": "One or more validation errors occurred.",
101+
"errors": {
102+
"description": [
103+
"'description' must not be empty."
104+
],
105+
"price": [
106+
"'price' must be greater than '0'."
107+
],
108+
"category.name": [
109+
"'name' must not be empty."
110+
]
111+
}
112+
},
113+
"statusCode": 400,
114+
"contentType": "application/problem+json"
115+
}
116+
```
117+
118+
## Installing from NuGet
119+
The [PosInformatique.FluentValidation.Json](https://www.nuget.org/packages/PosInformatique.FluentValidation.Json/)
120+
library is available directly on the
121+
[![Nuget](https://img.shields.io/nuget/v/PosInformatique.FluentValidation.Json)](https://www.nuget.org/packages/PosInformatique.FluentValidation.Json/)
122+
official website.
123+
124+
To download and install the library to your Visual Studio unit test projects use the following NuGet command line
125+
126+
```
127+
Install-Package PosInformatique.FluentValidation.Json
128+
```
129+
130+
## How it is work?
131+
132+
This library is really easy to use and just required to change the `ValidatorOptions.Global` configuration.
133+
134+
To use JSON property names when validating a DTO class, just call the `UseJsonProperties()` at the startup of the application.
135+
136+
For example, in ASP .NET application just call the `UseJsonProperties()` method at the initialization of the ASP .NET infrastructure:
137+
138+
```csharp
139+
public static void Main(string[] args)
140+
{
141+
var builder = WebApplication.CreateBuilder(args);
142+
143+
ValidatorOptions.Global.UseJsonProperties();
144+
145+
var app = builder.Build();
146+
147+
// Configure the HTTP request pipeline.
148+
app.UseAuthorization();
149+
150+
app.MapControllers();
151+
152+
app.Run();
153+
}
154+
```
155+
156+
And **THAT ALL !!**.
157+
158+
Next, you use your own validation strategy depending of the context usage.
159+
For example, if you ASP .NET Core to create an Web API, you can use the following code
160+
and returns an error as JSON problem format:
161+
162+
```json
163+
[ApiController]
164+
[Route("[controller]")]
165+
public class ProductController : ControllerBase
166+
{
167+
private readonly IValidator<Product> validator;
168+
169+
public ProductController(IValidator<Product> validator)
170+
{
171+
this.validator = validator;
172+
}
173+
174+
[HttpPost]
175+
public IResult Post(Product product)
176+
{
177+
var result = this.validator.Validate(product);
178+
179+
if (!result.IsValid)
180+
{
181+
return Results.ValidationProblem(result.ToDictionary());
182+
}
183+
184+
return Results.Ok();
185+
}
186+
}
187+
```
188+
189+
Do not hesitate to read the
190+
[FluentValidation ASP .NET Integration](https://docs.fluentvalidation.net/en/latest/aspnet.html)
191+
documentation for more information.
192+
193+
## JSON serialization library
194+
This library use the JSON property names specified by the `[JsonPropertyName]` attributes
195+
with the Microsoft `System.Text.Json`.
196+
197+
This library **DO NOT** use the property names specified by the `[JsonProperty]` attributes
198+
of the `Newtonsoft.Json` library.
199+
200+
## Library dependencies
201+
- The [PosInformatique.FluentValidation.Json](https://www.nuget.org/packages/PosInformatique.FluentValidation.Json/) library
202+
target the .NET Standard 2.0 and can be used with various of .NET architecture (.NET Core, .NET Framework,...).
203+
204+
- The [PosInformatique.FluentValidation.Json](https://www.nuget.org/packages/PosInformatique.FluentValidation.Json/) library
205+
use the 4.6.0 version of the [System.Text.Json](https://www.nuget.org/packages/System.Text.Json/) NuGet package
206+
and can be used with old projects that target this library version and earlier.

0 commit comments

Comments
 (0)