Skip to content

Commit 443ac29

Browse files
committed
initial commit
0 parents  commit 443ac29

File tree

16 files changed

+550
-0
lines changed

16 files changed

+550
-0
lines changed

.github/workflows/Build.yaml

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
name: FluentValidation.AutoValidation [Build]
2+
3+
env:
4+
JAVA_VERSION: 17
5+
JAVA_DISTRIBUTION: microsoft
6+
DOTNET_VERSION: 7.0.x
7+
DOTNET_BUILD_CONFIGURATION: Release
8+
SONAR_PATH: .\.sonar\scanner
9+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
10+
SONAR_HOST: https://sonarcloud.io
11+
SONAR_ORGANIZATION: sharpgrip
12+
SONAR_PROJECT: SharpGrip_FluentValidation.AutoValidation
13+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
14+
15+
on:
16+
workflow_dispatch:
17+
push:
18+
branches:
19+
- 'master'
20+
- 'develop'
21+
22+
jobs:
23+
build:
24+
runs-on: windows-latest
25+
26+
steps:
27+
- name: Checkout
28+
uses: actions/checkout@v3
29+
with:
30+
fetch-depth: 0
31+
32+
- name: Set up Java
33+
uses: actions/setup-java@v3
34+
with:
35+
java-version: ${{ env.JAVA_VERSION }}
36+
distribution: ${{ env.JAVA_DISTRIBUTION }}
37+
38+
- name: Setup .NET
39+
uses: actions/setup-dotnet@v3
40+
with:
41+
dotnet-version: ${{ env.DOTNET_VERSION }}
42+
43+
- name: Install dotnet-coverage
44+
shell: powershell
45+
run: dotnet tool install --global dotnet-coverage
46+
47+
- name: Install SonarCloud scanner
48+
shell: powershell
49+
run: |
50+
New-Item -Path ${{ env.SONAR_PATH }} -ItemType Directory -Force
51+
dotnet tool update dotnet-sonarscanner --tool-path ${{ env.SONAR_PATH }}
52+
53+
- name: Build solution
54+
run: dotnet build -c ${{ env.DOTNET_BUILD_CONFIGURATION }} /warnaserror
55+
56+
- name: Test solution
57+
run: dotnet test --no-build -c ${{ env.DOTNET_BUILD_CONFIGURATION }} --verbosity normal
58+
59+
- name: Cleanup solution
60+
run: dotnet clean
61+
62+
- name: Analyze solution
63+
shell: powershell
64+
run: |
65+
.\.sonar\scanner\dotnet-sonarscanner begin /k:"${{ env.SONAR_PROJECT }}" /o:"${{ env.SONAR_ORGANIZATION }}" /d:sonar.token="${{ env.SONAR_TOKEN }}" /d:sonar.host.url="${{ env.SONAR_HOST }}" /d:sonar.cs.vscoveragexml.reportsPaths=coverage.xml
66+
dotnet build -c ${{ env.DOTNET_BUILD_CONFIGURATION }}
67+
dotnet-coverage collect "dotnet test -c ${{ env.DOTNET_BUILD_CONFIGURATION }}" -f xml -o "coverage.xml"
68+
.\.sonar\scanner\dotnet-sonarscanner end /d:sonar.token="${{ env.SONAR_TOKEN }}"

.github/workflows/Release.yaml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: FluentValidation.AutoValidation [Release]
2+
3+
env:
4+
DOTNET_VERSION: 7.0.x
5+
DOTNET_BUILD_CONFIGURATION: Release
6+
DOTNET_PACKAGES_OUTPUT_DIRECTORY: .nuget
7+
NUGET_SOURCE: https://api.nuget.org/v3/index.json
8+
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
9+
10+
on:
11+
push:
12+
tags:
13+
- "*"
14+
15+
jobs:
16+
build:
17+
runs-on: ubuntu-latest
18+
19+
steps:
20+
- name: Checkout
21+
uses: actions/checkout@v3
22+
with:
23+
fetch-depth: 0
24+
25+
- name: Setup .NET
26+
uses: actions/setup-dotnet@v3
27+
with:
28+
dotnet-version: ${{ env.DOTNET_VERSION }}
29+
30+
- name: Pack packages
31+
run: dotnet pack --configuration ${{ env.DOTNET_BUILD_CONFIGURATION }} --output "${{ env.DOTNET_PACKAGES_OUTPUT_DIRECTORY }}"
32+
33+
- name: Push packages
34+
run: dotnet nuget push "${{ env.DOTNET_PACKAGES_OUTPUT_DIRECTORY }}/*.nupkg" --source ${{ env.NUGET_SOURCE }} --api-key ${{ env.NUGET_API_KEY }}

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.idea/
2+
.nuget/
3+
NuGet/
4+
[Oo]bj/
5+
[Bb]in/
6+
.DS_Store
7+
*.DotSettings.user

CODE_OF_CONDUCT.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Contributor Covenant Code of Conduct
2+
3+
## Our Pledge
4+
5+
In the interest of fostering an open and welcoming environment, we as
6+
contributors and maintainers pledge to making participation in our project and
7+
our community a harassment-free experience for everyone, regardless of age, body
8+
size, disability, ethnicity, sex characteristics, gender identity and expression,
9+
level of experience, education, socio-economic status, nationality, personal
10+
appearance, race, religion, or sexual identity and orientation.
11+
12+
## Our Standards
13+
14+
Examples of behavior that contributes to creating a positive environment
15+
include:
16+
17+
* Using welcoming and inclusive language
18+
* Being respectful of differing viewpoints and experiences
19+
* Gracefully accepting constructive criticism
20+
* Focusing on what is best for the community
21+
* Showing empathy towards other community members
22+
23+
Examples of unacceptable behavior by participants include:
24+
25+
* The use of sexualized language or imagery and unwelcome sexual attention or
26+
advances
27+
* Trolling, insulting/derogatory comments, and personal or political attacks
28+
* Public or private harassment
29+
* Publishing others' private information, such as a physical or electronic
30+
address, without explicit permission
31+
* Other conduct which could reasonably be considered inappropriate in a
32+
professional setting
33+
34+
## Our Responsibilities
35+
36+
Project maintainers are responsible for clarifying the standards of acceptable
37+
behavior and are expected to take appropriate and fair corrective action in
38+
response to any instances of unacceptable behavior.
39+
40+
Project maintainers have the right and responsibility to remove, edit, or
41+
reject comments, commits, code, wiki edits, issues, and other contributions
42+
that are not aligned to this Code of Conduct, or to ban temporarily or
43+
permanently any contributor for other behaviors that they deem inappropriate,
44+
threatening, offensive, or harmful.
45+
46+
## Scope
47+
48+
This Code of Conduct applies both within project spaces and in public spaces
49+
when an individual is representing the project or its community. Examples of
50+
representing a project or community include using an official project e-mail
51+
address, posting via an official social media account, or acting as an appointed
52+
representative at an online or offline event. Representation of a project may be
53+
further defined and clarified by project maintainers.
54+
55+
## Enforcement
56+
57+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
58+
reported by contacting the project team at [email protected]. All
59+
complaints will be reviewed and investigated and will result in a response that
60+
is deemed necessary and appropriate to the circumstances. The project team is
61+
obligated to maintain confidentiality with regard to the reporter of an incident.
62+
Further details of specific enforcement policies may be posted separately.
63+
64+
Project maintainers who do not follow or enforce the Code of Conduct in good
65+
faith may face temporary or permanent repercussions as determined by other
66+
members of the project's leadership.
67+
68+
## Attribution
69+
70+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71+
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72+
73+
[homepage]: https://www.contributor-covenant.org
74+
75+
For answers to common questions about this code of conduct, see
76+
https://www.contributor-covenant.org/faq

Directory.Build.props

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<Project>
2+
<PropertyGroup>
3+
<Nullable>enable</Nullable>
4+
<LangVersion>8.0</LangVersion>
5+
<NoWarn>NU1701</NoWarn>
6+
<IncludeSymbols>true</IncludeSymbols>
7+
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
8+
</PropertyGroup>
9+
10+
<PropertyGroup>
11+
<PackageVersion>1.0.0-beta1</PackageVersion>
12+
<Company>SharpGrip</Company>
13+
<Authors>SharpGrip</Authors>
14+
<Copyright>SharpGrip</Copyright>
15+
<PackageLicenseExpression>MIT</PackageLicenseExpression>
16+
<PackageReadmeFile>README.md</PackageReadmeFile>
17+
<PackageProjectUrl>https://sharpgrip.net</PackageProjectUrl>
18+
<RepositoryUrl>https://github.com/SharpGrip/FluentValidation.AutoValidation</RepositoryUrl>
19+
<RepositoryType>git</RepositoryType>
20+
</PropertyGroup>
21+
</Project>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<RootNamespace>SharpGrip.FluentValidation.AutoValidation.Endpoints</RootNamespace>
5+
</PropertyGroup>
6+
7+
<PropertyGroup>
8+
<TargetFramework>net7.0</TargetFramework>
9+
<AssemblyName>SharpGrip.FluentValidation.AutoValidation.Endpoints</AssemblyName>
10+
<PackageId>SharpGrip.FluentValidation.AutoValidation.Endpoints</PackageId>
11+
<Title>SharpGrip FluentValidation AutoValidation Endpoints</Title>
12+
<Description>SharpGrip FluentValidation AutoValidation Endpoints is an extension of the FluentValidation library enabling automatic asynchronous validation in minimal APIs (endpoints).</Description>
13+
<PackageTags>sharpgrip;validation;fluent-validation;minimal-api</PackageTags>
14+
</PropertyGroup>
15+
16+
<ItemGroup>
17+
<None Include="..\README.md" Pack="true" PackagePath="\" />
18+
</ItemGroup>
19+
20+
<ItemGroup>
21+
<FrameworkReference Include="Microsoft.AspNetCore.App" />
22+
</ItemGroup>
23+
24+
<ItemGroup>
25+
<ProjectReference Include="..\FluentValidation.AutoValidation.Shared\FluentValidation.AutoValidation.Shared.csproj" />
26+
</ItemGroup>
27+
28+
</Project>
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using Microsoft.AspNetCore.Builder;
2+
using Microsoft.AspNetCore.Http;
3+
using Microsoft.AspNetCore.Routing;
4+
using SharpGrip.FluentValidation.AutoValidation.Endpoints.Filters;
5+
6+
namespace SharpGrip.FluentValidation.AutoValidation.Endpoints.Extensions
7+
{
8+
public static class EndpointRouteExtensions
9+
{
10+
public static RouteHandlerBuilder AddFluentValidationAutoValidation(this RouteHandlerBuilder routeHandlerBuilder)
11+
{
12+
routeHandlerBuilder.AddEndpointFilter<FluentValidationAutoValidationEndpointFilter>();
13+
14+
return routeHandlerBuilder;
15+
}
16+
17+
public static RouteGroupBuilder AddFluentValidationAutoValidation(this RouteGroupBuilder routeGroupBuilder)
18+
{
19+
routeGroupBuilder.AddEndpointFilter<FluentValidationAutoValidationEndpointFilter>();
20+
21+
return routeGroupBuilder;
22+
}
23+
}
24+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using FluentValidation;
6+
using Microsoft.AspNetCore.Http;
7+
using SharpGrip.FluentValidation.AutoValidation.Shared.Extensions;
8+
9+
namespace SharpGrip.FluentValidation.AutoValidation.Endpoints.Filters
10+
{
11+
public class FluentValidationAutoValidationEndpointFilter : IEndpointFilter
12+
{
13+
private readonly IServiceProvider serviceProvider;
14+
15+
public FluentValidationAutoValidationEndpointFilter(IServiceProvider serviceProvider)
16+
{
17+
this.serviceProvider = serviceProvider;
18+
}
19+
20+
public async ValueTask<object?> InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next)
21+
{
22+
for (var i = 0; i < context.Arguments.Count; i++)
23+
{
24+
var argument = context.Arguments[i];
25+
26+
if (argument == null)
27+
{
28+
continue;
29+
}
30+
31+
if (serviceProvider.GetValidator(argument.GetType()) is IValidator validator)
32+
{
33+
var validationResult = await validator.ValidateAsync(new ValidationContext<object>(argument), context.HttpContext.RequestAborted);
34+
35+
if (!validationResult.IsValid)
36+
{
37+
var errors = new Dictionary<string, string[]>();
38+
39+
foreach (var errorGrouping in validationResult.Errors.GroupBy(error => error.PropertyName))
40+
{
41+
errors.Add(errorGrouping.Key, errorGrouping.Select(error => error.ErrorMessage).ToArray());
42+
}
43+
44+
return TypedResults.ValidationProblem(errors);
45+
}
46+
}
47+
}
48+
49+
return await next(context);
50+
}
51+
}
52+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<RootNamespace>SharpGrip.FluentValidation.AutoValidation.Mvc</RootNamespace>
5+
</PropertyGroup>
6+
7+
<PropertyGroup>
8+
<TargetFrameworks>netcoreapp3.1;net6.0;net7.0</TargetFrameworks>
9+
<AssemblyName>SharpGrip.FluentValidation.AutoValidation.Mvc</AssemblyName>
10+
<PackageId>SharpGrip.FluentValidation.AutoValidation.Mvc</PackageId>
11+
<Title>SharpGrip FluentValidation AutoValidation MVC</Title>
12+
<Description>SharpGrip FluentValidation AutoValidation MVC is an extension of the FluentValidation library enabling automatic asynchronous validation in MVC controllers.</Description>
13+
<PackageTags>sharpgrip;validation;fluent-validation;mvc</PackageTags>
14+
</PropertyGroup>
15+
16+
<ItemGroup>
17+
<None Include="..\README.md" Pack="true" PackagePath="\" />
18+
</ItemGroup>
19+
20+
<ItemGroup>
21+
<FrameworkReference Include="Microsoft.AspNetCore.App" />
22+
</ItemGroup>
23+
24+
<ItemGroup>
25+
<ProjectReference Include="..\FluentValidation.AutoValidation.Shared\FluentValidation.AutoValidation.Shared.csproj" />
26+
</ItemGroup>
27+
28+
</Project>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using Microsoft.AspNetCore.Mvc.Infrastructure;
3+
using Microsoft.Extensions.DependencyInjection;
4+
using Microsoft.Extensions.Logging.Abstractions;
5+
using SharpGrip.FluentValidation.AutoValidation.Mvc.Filters;
6+
7+
namespace SharpGrip.FluentValidation.AutoValidation.Mvc.Extensions
8+
{
9+
public static class ServiceCollectionExtensions
10+
{
11+
public static IServiceCollection AddFluentValidationAutoValidation(this IServiceCollection serviceCollection)
12+
{
13+
var modelStateInvalidFilter = new ModelStateInvalidFilter(new ApiBehaviorOptions {InvalidModelStateResponseFactory = context => new OkResult()}, NullLogger.Instance);
14+
15+
// Make sure we insert the `FluentValidationAutoValidationActionFilter` before the built-in `ModelStateInvalidFilter` to prevent it short-circuiting the request.
16+
serviceCollection.Configure<MvcOptions>(options => options.Filters.Add<FluentValidationAutoValidationActionFilter>(modelStateInvalidFilter.Order - 1));
17+
18+
return serviceCollection;
19+
}
20+
}
21+
}

0 commit comments

Comments
 (0)