From 443ac29c76092998a9a901c11eac8798ef27ce72 Mon Sep 17 00:00:00 2001 From: Mauro van der Gun Date: Wed, 16 Aug 2023 13:33:45 -0400 Subject: [PATCH] initial commit --- .github/workflows/Build.yaml | 68 +++++++++++++++++ .github/workflows/Release.yaml | 34 +++++++++ .gitignore | 7 ++ CODE_OF_CONDUCT.md | 76 +++++++++++++++++++ Directory.Build.props | 21 +++++ ...Validation.AutoValidation.Endpoints.csproj | 28 +++++++ .../src/Extensions/EndpointRouteExtensions.cs | 24 ++++++ ...tValidationAutoValidationEndpointFilter.cs | 52 +++++++++++++ ...FluentValidation.AutoValidation.Mvc.csproj | 28 +++++++ .../Extensions/ServiceCollectionExtensions.cs | 21 +++++ ...entValidationAutoValidationActionFilter.cs | 63 +++++++++++++++ ...entValidation.AutoValidation.Shared.csproj | 16 ++++ .../Extensions/ServiceProviderExtensions.cs | 13 ++++ FluentValidation.AutoValidation.sln | 28 +++++++ LICENSE | 21 +++++ README.md | 50 ++++++++++++ 16 files changed, 550 insertions(+) create mode 100644 .github/workflows/Build.yaml create mode 100644 .github/workflows/Release.yaml create mode 100644 .gitignore create mode 100644 CODE_OF_CONDUCT.md create mode 100644 Directory.Build.props create mode 100644 FluentValidation.AutoValidation.Endpoints/FluentValidation.AutoValidation.Endpoints.csproj create mode 100644 FluentValidation.AutoValidation.Endpoints/src/Extensions/EndpointRouteExtensions.cs create mode 100644 FluentValidation.AutoValidation.Endpoints/src/Filters/FluentValidationAutoValidationEndpointFilter.cs create mode 100644 FluentValidation.AutoValidation.Mvc/FluentValidation.AutoValidation.Mvc.csproj create mode 100644 FluentValidation.AutoValidation.Mvc/src/Extensions/ServiceCollectionExtensions.cs create mode 100644 FluentValidation.AutoValidation.Mvc/src/Filters/FluentValidationAutoValidationActionFilter.cs create mode 100644 FluentValidation.AutoValidation.Shared/FluentValidation.AutoValidation.Shared.csproj create mode 100644 FluentValidation.AutoValidation.Shared/src/Extensions/ServiceProviderExtensions.cs create mode 100644 FluentValidation.AutoValidation.sln create mode 100644 LICENSE create mode 100644 README.md diff --git a/.github/workflows/Build.yaml b/.github/workflows/Build.yaml new file mode 100644 index 0000000..ac0c193 --- /dev/null +++ b/.github/workflows/Build.yaml @@ -0,0 +1,68 @@ +name: FluentValidation.AutoValidation [Build] + +env: + JAVA_VERSION: 17 + JAVA_DISTRIBUTION: microsoft + DOTNET_VERSION: 7.0.x + DOTNET_BUILD_CONFIGURATION: Release + SONAR_PATH: .\.sonar\scanner + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + SONAR_HOST: https://sonarcloud.io + SONAR_ORGANIZATION: sharpgrip + SONAR_PROJECT: SharpGrip_FluentValidation.AutoValidation + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +on: + workflow_dispatch: + push: + branches: + - 'master' + - 'develop' + +jobs: + build: + runs-on: windows-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set up Java + uses: actions/setup-java@v3 + with: + java-version: ${{ env.JAVA_VERSION }} + distribution: ${{ env.JAVA_DISTRIBUTION }} + + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Install dotnet-coverage + shell: powershell + run: dotnet tool install --global dotnet-coverage + + - name: Install SonarCloud scanner + shell: powershell + run: | + New-Item -Path ${{ env.SONAR_PATH }} -ItemType Directory -Force + dotnet tool update dotnet-sonarscanner --tool-path ${{ env.SONAR_PATH }} + + - name: Build solution + run: dotnet build -c ${{ env.DOTNET_BUILD_CONFIGURATION }} /warnaserror + + - name: Test solution + run: dotnet test --no-build -c ${{ env.DOTNET_BUILD_CONFIGURATION }} --verbosity normal + + - name: Cleanup solution + run: dotnet clean + + - name: Analyze solution + shell: powershell + run: | + .\.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 + dotnet build -c ${{ env.DOTNET_BUILD_CONFIGURATION }} + dotnet-coverage collect "dotnet test -c ${{ env.DOTNET_BUILD_CONFIGURATION }}" -f xml -o "coverage.xml" + .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.token="${{ env.SONAR_TOKEN }}" \ No newline at end of file diff --git a/.github/workflows/Release.yaml b/.github/workflows/Release.yaml new file mode 100644 index 0000000..5982074 --- /dev/null +++ b/.github/workflows/Release.yaml @@ -0,0 +1,34 @@ +name: FluentValidation.AutoValidation [Release] + +env: + DOTNET_VERSION: 7.0.x + DOTNET_BUILD_CONFIGURATION: Release + DOTNET_PACKAGES_OUTPUT_DIRECTORY: .nuget + NUGET_SOURCE: https://api.nuget.org/v3/index.json + NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} + +on: + push: + tags: + - "*" + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Pack packages + run: dotnet pack --configuration ${{ env.DOTNET_BUILD_CONFIGURATION }} --output "${{ env.DOTNET_PACKAGES_OUTPUT_DIRECTORY }}" + + - name: Push packages + run: dotnet nuget push "${{ env.DOTNET_PACKAGES_OUTPUT_DIRECTORY }}/*.nupkg" --source ${{ env.NUGET_SOURCE }} --api-key ${{ env.NUGET_API_KEY }} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1a7e992 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.idea/ +.nuget/ +NuGet/ +[Oo]bj/ +[Bb]in/ +.DS_Store +*.DotSettings.user \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..17df721 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at info@sharpgrip.net. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..bc77f7d --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,21 @@ + + + enable + 8.0 + NU1701 + true + snupkg + + + + 1.0.0-beta1 + SharpGrip + SharpGrip + SharpGrip + MIT + README.md + https://sharpgrip.net + https://github.com/SharpGrip/FluentValidation.AutoValidation + git + + \ No newline at end of file diff --git a/FluentValidation.AutoValidation.Endpoints/FluentValidation.AutoValidation.Endpoints.csproj b/FluentValidation.AutoValidation.Endpoints/FluentValidation.AutoValidation.Endpoints.csproj new file mode 100644 index 0000000..009fd8f --- /dev/null +++ b/FluentValidation.AutoValidation.Endpoints/FluentValidation.AutoValidation.Endpoints.csproj @@ -0,0 +1,28 @@ + + + + SharpGrip.FluentValidation.AutoValidation.Endpoints + + + + net7.0 + SharpGrip.FluentValidation.AutoValidation.Endpoints + SharpGrip.FluentValidation.AutoValidation.Endpoints + SharpGrip FluentValidation AutoValidation Endpoints + SharpGrip FluentValidation AutoValidation Endpoints is an extension of the FluentValidation library enabling automatic asynchronous validation in minimal APIs (endpoints). + sharpgrip;validation;fluent-validation;minimal-api + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FluentValidation.AutoValidation.Endpoints/src/Extensions/EndpointRouteExtensions.cs b/FluentValidation.AutoValidation.Endpoints/src/Extensions/EndpointRouteExtensions.cs new file mode 100644 index 0000000..8daba86 --- /dev/null +++ b/FluentValidation.AutoValidation.Endpoints/src/Extensions/EndpointRouteExtensions.cs @@ -0,0 +1,24 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; +using SharpGrip.FluentValidation.AutoValidation.Endpoints.Filters; + +namespace SharpGrip.FluentValidation.AutoValidation.Endpoints.Extensions +{ + public static class EndpointRouteExtensions + { + public static RouteHandlerBuilder AddFluentValidationAutoValidation(this RouteHandlerBuilder routeHandlerBuilder) + { + routeHandlerBuilder.AddEndpointFilter(); + + return routeHandlerBuilder; + } + + public static RouteGroupBuilder AddFluentValidationAutoValidation(this RouteGroupBuilder routeGroupBuilder) + { + routeGroupBuilder.AddEndpointFilter(); + + return routeGroupBuilder; + } + } +} \ No newline at end of file diff --git a/FluentValidation.AutoValidation.Endpoints/src/Filters/FluentValidationAutoValidationEndpointFilter.cs b/FluentValidation.AutoValidation.Endpoints/src/Filters/FluentValidationAutoValidationEndpointFilter.cs new file mode 100644 index 0000000..6c74da4 --- /dev/null +++ b/FluentValidation.AutoValidation.Endpoints/src/Filters/FluentValidationAutoValidationEndpointFilter.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using FluentValidation; +using Microsoft.AspNetCore.Http; +using SharpGrip.FluentValidation.AutoValidation.Shared.Extensions; + +namespace SharpGrip.FluentValidation.AutoValidation.Endpoints.Filters +{ + public class FluentValidationAutoValidationEndpointFilter : IEndpointFilter + { + private readonly IServiceProvider serviceProvider; + + public FluentValidationAutoValidationEndpointFilter(IServiceProvider serviceProvider) + { + this.serviceProvider = serviceProvider; + } + + public async ValueTask InvokeAsync(EndpointFilterInvocationContext context, EndpointFilterDelegate next) + { + for (var i = 0; i < context.Arguments.Count; i++) + { + var argument = context.Arguments[i]; + + if (argument == null) + { + continue; + } + + if (serviceProvider.GetValidator(argument.GetType()) is IValidator validator) + { + var validationResult = await validator.ValidateAsync(new ValidationContext(argument), context.HttpContext.RequestAborted); + + if (!validationResult.IsValid) + { + var errors = new Dictionary(); + + foreach (var errorGrouping in validationResult.Errors.GroupBy(error => error.PropertyName)) + { + errors.Add(errorGrouping.Key, errorGrouping.Select(error => error.ErrorMessage).ToArray()); + } + + return TypedResults.ValidationProblem(errors); + } + } + } + + return await next(context); + } + } +} \ No newline at end of file diff --git a/FluentValidation.AutoValidation.Mvc/FluentValidation.AutoValidation.Mvc.csproj b/FluentValidation.AutoValidation.Mvc/FluentValidation.AutoValidation.Mvc.csproj new file mode 100644 index 0000000..50149ab --- /dev/null +++ b/FluentValidation.AutoValidation.Mvc/FluentValidation.AutoValidation.Mvc.csproj @@ -0,0 +1,28 @@ + + + + SharpGrip.FluentValidation.AutoValidation.Mvc + + + + netcoreapp3.1;net6.0;net7.0 + SharpGrip.FluentValidation.AutoValidation.Mvc + SharpGrip.FluentValidation.AutoValidation.Mvc + SharpGrip FluentValidation AutoValidation MVC + SharpGrip FluentValidation AutoValidation MVC is an extension of the FluentValidation library enabling automatic asynchronous validation in MVC controllers. + sharpgrip;validation;fluent-validation;mvc + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FluentValidation.AutoValidation.Mvc/src/Extensions/ServiceCollectionExtensions.cs b/FluentValidation.AutoValidation.Mvc/src/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..70a1e3a --- /dev/null +++ b/FluentValidation.AutoValidation.Mvc/src/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging.Abstractions; +using SharpGrip.FluentValidation.AutoValidation.Mvc.Filters; + +namespace SharpGrip.FluentValidation.AutoValidation.Mvc.Extensions +{ + public static class ServiceCollectionExtensions + { + public static IServiceCollection AddFluentValidationAutoValidation(this IServiceCollection serviceCollection) + { + var modelStateInvalidFilter = new ModelStateInvalidFilter(new ApiBehaviorOptions {InvalidModelStateResponseFactory = context => new OkResult()}, NullLogger.Instance); + + // Make sure we insert the `FluentValidationAutoValidationActionFilter` before the built-in `ModelStateInvalidFilter` to prevent it short-circuiting the request. + serviceCollection.Configure(options => options.Filters.Add(modelStateInvalidFilter.Order - 1)); + + return serviceCollection; + } + } +} \ No newline at end of file diff --git a/FluentValidation.AutoValidation.Mvc/src/Filters/FluentValidationAutoValidationActionFilter.cs b/FluentValidation.AutoValidation.Mvc/src/Filters/FluentValidationAutoValidationActionFilter.cs new file mode 100644 index 0000000..7b7c802 --- /dev/null +++ b/FluentValidation.AutoValidation.Mvc/src/Filters/FluentValidationAutoValidationActionFilter.cs @@ -0,0 +1,63 @@ +using System; +using System.Threading.Tasks; +using FluentValidation; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using SharpGrip.FluentValidation.AutoValidation.Shared.Extensions; + +namespace SharpGrip.FluentValidation.AutoValidation.Mvc.Filters +{ + public class FluentValidationAutoValidationActionFilter : IAsyncActionFilter + { + private readonly IServiceProvider serviceProvider; + + public FluentValidationAutoValidationActionFilter(IServiceProvider serviceProvider) + { + this.serviceProvider = serviceProvider; + } + + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + if (context.Controller is ControllerBase controllerBase) + { + foreach (var parameter in context.ActionDescriptor.Parameters) + { + var subject = context.ActionArguments[parameter.Name]; + var parameterType = parameter.ParameterType; + + // ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract + var bindingSource = parameter.BindingInfo?.BindingSource; + + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (subject != null && (bindingSource == BindingSource.Body || (bindingSource == BindingSource.Query && parameterType.IsClass))) + { + if (serviceProvider.GetValidator(parameterType) is IValidator validator) + { + var validationResult = await validator.ValidateAsync(new ValidationContext(subject), context.HttpContext.RequestAborted); + + if (!validationResult.IsValid) + { + foreach (var error in validationResult.Errors) + { + context.ModelState.AddModelError(error.PropertyName, error.ErrorMessage); + } + } + } + } + } + + if (!context.ModelState.IsValid) + { + var validationProblem = controllerBase.ProblemDetailsFactory.CreateValidationProblemDetails(context.HttpContext, context.ModelState); + + context.Result = new BadRequestObjectResult(validationProblem); + + return; + } + } + + await next(); + } + } +} \ No newline at end of file diff --git a/FluentValidation.AutoValidation.Shared/FluentValidation.AutoValidation.Shared.csproj b/FluentValidation.AutoValidation.Shared/FluentValidation.AutoValidation.Shared.csproj new file mode 100644 index 0000000..2cffda3 --- /dev/null +++ b/FluentValidation.AutoValidation.Shared/FluentValidation.AutoValidation.Shared.csproj @@ -0,0 +1,16 @@ + + + + SharpGrip.FluentValidation.AutoValidation.Shared + + + + netstandard2.0;netstandard2.1 + false + + + + + + + \ No newline at end of file diff --git a/FluentValidation.AutoValidation.Shared/src/Extensions/ServiceProviderExtensions.cs b/FluentValidation.AutoValidation.Shared/src/Extensions/ServiceProviderExtensions.cs new file mode 100644 index 0000000..52cbabc --- /dev/null +++ b/FluentValidation.AutoValidation.Shared/src/Extensions/ServiceProviderExtensions.cs @@ -0,0 +1,13 @@ +using System; +using FluentValidation; + +namespace SharpGrip.FluentValidation.AutoValidation.Shared.Extensions +{ + public static class ServiceProviderExtensions + { + public static object? GetValidator(this IServiceProvider serviceProvider, Type type) + { + return serviceProvider.GetService(typeof(IValidator<>).MakeGenericType(type)); + } + } +} \ No newline at end of file diff --git a/FluentValidation.AutoValidation.sln b/FluentValidation.AutoValidation.sln new file mode 100644 index 0000000..7761041 --- /dev/null +++ b/FluentValidation.AutoValidation.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentValidation.AutoValidation.Endpoints", "FluentValidation.AutoValidation.Endpoints\FluentValidation.AutoValidation.Endpoints.csproj", "{8743E1EF-94ED-4B9C-B117-3D6B533334D0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentValidation.AutoValidation.Mvc", "FluentValidation.AutoValidation.Mvc\FluentValidation.AutoValidation.Mvc.csproj", "{84A6D838-49F2-4245-BAA4-E4B7B69D3D0D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentValidation.AutoValidation.Shared", "FluentValidation.AutoValidation.Shared\FluentValidation.AutoValidation.Shared.csproj", "{EFB3047F-34BD-4A84-86B9-52F96E2D240D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8743E1EF-94ED-4B9C-B117-3D6B533334D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8743E1EF-94ED-4B9C-B117-3D6B533334D0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8743E1EF-94ED-4B9C-B117-3D6B533334D0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8743E1EF-94ED-4B9C-B117-3D6B533334D0}.Release|Any CPU.Build.0 = Release|Any CPU + {84A6D838-49F2-4245-BAA4-E4B7B69D3D0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {84A6D838-49F2-4245-BAA4-E4B7B69D3D0D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {84A6D838-49F2-4245-BAA4-E4B7B69D3D0D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {84A6D838-49F2-4245-BAA4-E4B7B69D3D0D}.Release|Any CPU.Build.0 = Release|Any CPU + {EFB3047F-34BD-4A84-86B9-52F96E2D240D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EFB3047F-34BD-4A84-86B9-52F96E2D240D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EFB3047F-34BD-4A84-86B9-52F96E2D240D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EFB3047F-34BD-4A84-86B9-52F96E2D240D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0513a2f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 SharpGrip + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..0be3e6b --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ +# SharpGrip FluentValidation AutoValidation + +## Builds + +[![FluentValidation.AutoValidation [Build]](https://github.com/SharpGrip/FluentValidation.AutoValidation/actions/workflows/Build.yaml/badge.svg)](https://github.com/SharpGrip/FluentValidation.AutoValidation/actions/workflows/Build.yaml) + +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=SharpGrip_FluentValidation.AutoValidation&metric=alert_status)](https://sonarcloud.io/summary/overall?id=SharpGrip_FluentValidation.AutoValidation) \ +[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=SharpGrip_FluentValidation.AutoValidation&metric=sqale_rating)](https://sonarcloud.io/summary/overall?id=SharpGrip_FluentValidation.AutoValidation) \ +[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=SharpGrip_FluentValidation.AutoValidation&metric=reliability_rating)](https://sonarcloud.io/summary/overall?id=SharpGrip_FluentValidation.AutoValidation) \ +[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=SharpGrip_FluentValidation.AutoValidation&metric=security_rating)](https://sonarcloud.io/summary/overall?id=SharpGrip_FluentValidation.AutoValidation) \ +[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=SharpGrip_FluentValidation.AutoValidation&metric=coverage)](https://sonarcloud.io/summary/overall?id=SharpGrip_FluentValidation.AutoValidation) + +## Introduction + +SharpGrip FluentValidation AutoValidation is an extension of the [FluentValidation](https://github.com/FluentValidation/FluentValidation) library enabling automatic asynchronous validation in MVC controllers and minimal APIs (endpoints). +The library [FluentValidation.AspNetCore](https://github.com/FluentValidation/FluentValidation.AspNetCore) is no longer being maintained and is unsupported. As a result, support for automatic validation provided by this library is no longer available. +This library re-introduces this functionality for MVC controllers and introduces automation validation for minimal APIs (endpoints). It enables developers to easily implement automatic validation in their projects. + +## Installation + +Register your validators with the Microsoft DI service container, for reference please see https://docs.fluentvalidation.net/en/latest/di.html. + +### MVC controllers +For MVC controllers reference NuGet package `SharpGrip.FluentValidation.AutoValidation.Mvc` (https://www.nuget.org/packages/SharpGrip.FluentValidation.AutoValidation.Mvc). + +### Minimal APIs +For minimal APIs (endpoints) reference NuGet package `SharpGrip.FluentValidation.AutoValidation.Endpoints` (https://www.nuget.org/packages/SharpGrip.FluentValidation.AutoValidation.Endpoints). + +## Usage + +### MVC controllers + +``` +using SharpGrip.FluentValidation.AutoValidation.Mvc.Extensions; + +builder.Services.AddFluentValidationAutoValidation(); +``` + +### Minimal APIs (endpoints) + +Enabling minimal API (endpoint) automatic validation can be done on both route groups and routes. + +``` +using SharpGrip.FluentValidation.AutoValidation.Endpoints.Extensions; + +var endpointGroup = app.MapGroup("/some-group").AddFluentValidationAutoValidation(); +endpointGroup.MapPost("/", (TestCreateModel testCreateModel) => $"Hello {testCreateModel.Name}"); + +app.MapPost("/", (TestCreateModel testCreateModel) => $"Hello again {testCreateModel.Name}").AddFluentValidationAutoValidation(); +``` \ No newline at end of file