micro-elements - MicroElements.Swashbuckle.FluentValidation 0.0.2

Swagger ISchemaFilter that uses FluentValidation validators instead System.ComponentModel based attributes.

PM> Install-Package MicroElements.Swashbuckle.FluentValidation -Version 0.0.2 -Source https://www.myget.org/F/micro-elements/api/v3/index.json

Copy to clipboard

> nuget.exe install MicroElements.Swashbuckle.FluentValidation -Version 0.0.2 -Source https://www.myget.org/F/micro-elements/api/v3/index.json

Copy to clipboard

> dotnet add package MicroElements.Swashbuckle.FluentValidation --version 0.0.2 --source https://www.myget.org/F/micro-elements/api/v3/index.json

Copy to clipboard
<PackageReference Include="MicroElements.Swashbuckle.FluentValidation" Version="0.0.2" />
Copy to clipboard
source https://www.myget.org/F/micro-elements/api/v3/index.json

nuget MicroElements.Swashbuckle.FluentValidation  ~> 0.0.2
Copy to clipboard

> choco install MicroElements.Swashbuckle.FluentValidation --version 0.0.2 --source https://www.myget.org/F/micro-elements/api/v2

Copy to clipboard
Import-Module PowerShellGet
Register-PSRepository -Name "micro-elements" -SourceLocation "https://www.myget.org/F/micro-elements/api/v2"
Install-Module -Name "MicroElements.Swashbuckle.FluentValidation" -RequiredVersion "0.0.2" -Repository "micro-elements" 
Copy to clipboard

MicroElements.Swashbuckle.FluentValidation

Use FluentValidation rules instead of ComponentModel attributes to define swagger schema.

Note: For WebApi see: https://github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation.WebApi

Statuses

License NuGetVersion NuGetDownloads MyGetVersion

Build and publish AppVeyor Coverage Status

Gitter

Supporting the project

MicroElements.Swashbuckle.FluentValidation is developed and supported by @petriashev for free in his spare time. If you find MicroElements.Swashbuckle.FluentValidation useful, please consider financially supporting the project via OpenCollective which will help keep the project going 🙏.

Usage

1. Minimal API

MinimalApi.csproj

<Project Sdk="Microsoft.NET.Sdk.Web">

    <PropertyGroup>
        <TargetFramework>net7.0</TargetFramework>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="FluentValidation.AspNetCore" Version="11.2.2" />
        <PackageReference Include="MicroElements.Swashbuckle.FluentValidation" Version="6.0.0" />
        <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.2" />
        <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
    </ItemGroup>
    
</Project>

Program.cs

using FluentValidation;
using FluentValidation.AspNetCore;
using MicroElements.Swashbuckle.FluentValidation.AspNetCore;

var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;

// Asp.Net stuff
services.AddControllers();
services.AddEndpointsApiExplorer();

// Add Swagger
services.AddSwaggerGen();

// Add FV
services.AddFluentValidationAutoValidation();
services.AddFluentValidationClientsideAdapters();

// Add FV validators
services.AddValidatorsFromAssemblyContaining<Program>();

// Add FV Rules to swagger
services.AddFluentValidationRulesToSwagger();

var app = builder.Build();

// Use Swagger
app.UseSwagger();
app.UseSwaggerUI();

app.MapControllers();

app.Run();

2. AspNetCore WebApi

Reference packages in your web project

<PackageReference Include="FluentValidation.AspNetCore" Version="11.1.0" />
<PackageReference Include="MicroElements.Swashbuckle.FluentValidation" Version="6.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.0" />

Change Startup.cs

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    // Asp.net stuff
    services.AddControllers();
    
    // HttpContextValidatorRegistry requires access to HttpContext
    services.AddHttpContextAccessor();

    // Register FV validators
    services.AddValidatorsFromAssemblyContaining<Startup>(lifetime: ServiceLifetime.Scoped);

    // Add FV to Asp.net
    services.AddFluentValidationAutoValidation();

    // Add swagger
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
    });

    // [Optional] Add INameResolver (SystemTextJsonNameResolver will be registered by default)
    // services.AddSingleton<INameResolver, CustomNameResolver>();

    // Adds FluentValidationRules staff to Swagger. (Minimal configuration)
    services.AddFluentValidationRulesToSwagger();

    // [Optional] Configure generation options for your needs. Also can be done with services.Configure<SchemaGenerationOptions>
    // services.AddFluentValidationRulesToSwagger(options =>
    // {
    //     options.SetNotNullableIfMinLengthGreaterThenZero = true;
    //     options.UseAllOffForMultipleRules = true;
    // });

    // Adds logging
    services.AddLogging(builder => builder.AddConsole());
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });

    // Adds swagger
    app.UseSwagger();

    // Adds swagger UI
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
    });
}

Version compatibility

MicroElements.Swashbuckle.FluentValidation Swashbuckle.AspNetCore FluentValidation
[1.1.0, 2.0.0) [3.0.0, 4.0.0) >=7.2.0
[2.0.0, 3.0.0) [4.0.0, 5.0.0) >=8.1.3
[3.0.0, 3.1.0) [5.0.0, 5.2.0) >=8.3.0
[3.1.0, 4.2.1) [5.2.0, 6.0.0) >=8.3.0
[4.2.0, 5.0.0) [5.5.1, 7.0.0) [9.0.0, 10)
[5.0.0, 6.0.0) [6.3.0, 7.0.0) [10.0.0, 12)

Sample application

See sample project: https://github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation/tree/master/samples/SampleWebApi

Supported validators

  • INotNullValidator (NotNull)
  • INotEmptyValidator (NotEmpty)
  • ILengthValidator (for strings: Length, MinimumLength, MaximumLength, ExactLength) (for arrays: MinItems, MaxItems)
  • IRegularExpressionValidator (Email, Matches)
  • IComparisonValidator (GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqual)
  • IBetweenValidator (InclusiveBetween, ExclusiveBetween)

Extensibility

You can register FluentValidationRule in ServiceCollection.

User defined rule name replaces default rule with the same. Full list of default rules can be get by FluentValidationRules.CreateDefaultRules()

List or default rules:

  • Required
  • NotEmpty
  • Length
  • Pattern
  • Comparison
  • Between

Example of rule:

new FluentValidationRule("Pattern")
{
    Matches = propertyValidator => propertyValidator is IRegularExpressionValidator,
    Apply = context =>
    {
        var regularExpressionValidator = (IRegularExpressionValidator)context.PropertyValidator;
        context.Schema.Properties[context.PropertyKey].Pattern = regularExpressionValidator.Expression;
    }
},

Samples

Swagger Sample model and validator

public class Sample
{
    public string PropertyWithNoRules { get; set; }

    public string NotNull { get; set; }
    public string NotEmpty { get; set; }
    public string EmailAddress { get; set; }
    public string RegexField { get; set; }

    public int ValueInRange { get; set; }
    public int ValueInRangeExclusive { get; set; }

    public float ValueInRangeFloat { get; set; }
    public double ValueInRangeDouble { get; set; }
}

public class SampleValidator : AbstractValidator<Sample>
{
    public SampleValidator()
    {
        RuleFor(sample => sample.NotNull).NotNull();
        RuleFor(sample => sample.NotEmpty).NotEmpty();
        RuleFor(sample => sample.EmailAddress).EmailAddress();
        RuleFor(sample => sample.RegexField).Matches(@"(\d{4})-(\d{2})-(\d{2})");

        RuleFor(sample => sample.ValueInRange).GreaterThanOrEqualTo(5).LessThanOrEqualTo(10);
        RuleFor(sample => sample.ValueInRangeExclusive).GreaterThan(5).LessThan(10);

        // WARNING: Swashbuckle implements minimum and maximim as int so you will loss fraction part of float and double numbers
        RuleFor(sample => sample.ValueInRangeFloat).InclusiveBetween(1.1f, 5.3f);
        RuleFor(sample => sample.ValueInRangeDouble).ExclusiveBetween(2.2, 7.5f);
    }
}

Swagger Sample model screenshot

SwaggerSample

Validator with Include

public class CustomerValidator : AbstractValidator<Customer>
{
    public CustomerValidator()
    {
        RuleFor(customer => customer.Surname).NotEmpty();
        RuleFor(customer => customer.Forename).NotEmpty().WithMessage("Please specify a first name");

        Include(new CustomerAddressValidator());
    }
}

internal class CustomerAddressValidator : AbstractValidator<Customer>
{
    public CustomerAddressValidator()
    {
        RuleFor(customer => customer.Address).Length(20, 250);
    }
}

Get params bounded to validatable models

MicroElements.Swashbuckle.FluentValidation updates swagger schema for operation parameters bounded to validatable models.

Defining rules dynamically from database

See BlogValidator in sample.

Common problems and workarounds

Error: System.InvalidOperationException: 'Cannot resolve 'IValidator<T>' from root provider because it requires scoped service 'TDependency'

Workarounds in order or preference:

Workaround 1 (Use HttpContextServiceProviderValidatorFactory) by @WarpSpideR

public void ConfigureServices(IServiceCollection services)
{
    // HttpContextServiceProviderValidatorFactory requires access to HttpContext
    services.AddHttpContextAccessor();

    services
        .AddMvc()
        // Adds fluent validators to Asp.net
        .AddFluentValidation(c =>
        {
            c.RegisterValidatorsFromAssemblyContaining<Startup>();
            // Optionally set validator factory if you have problems with scope resolve inside validators.
            c.ValidatorFactoryType = typeof(HttpContextServiceProviderValidatorFactory);
        });

Workaround 2 (Use ScopedSwaggerMiddleware)

Replace UseSwagger for UseScopedSwagger:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app
        .UseMvc()
        // Use scoped swagger if you have problems with scoped services in validators
        .UseScopedSwagger();

Workaround 3 (Set ValidateScopes to false)

public static IWebHost BuildWebHost(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        // Needed for using scoped services (for example DbContext) in validators
        .UseDefaultServiceProvider(options => options.ValidateScopes = false)
        .UseStartup<Startup>()
        .Build();

Problem: I cant use several validators of one type

Example: You split validator into several small validators but AspNetCore uses only one of them.

Workaround: Hide dependent validators with internal and use Include to include other validation rules to one "Main" validator.

Problem: I'm using FluentValidation or FluentValidation.DependencyInjectionExtensions instead of FluentValidation.AspNetCore

If you are using the more basic FluentValidation or FluentValidation.DependencyInjectionExtensions libraries, then they will not automatically register IValidatorFactory and you will get an error at runtime: "ValidatorFactory is not provided. Please register FluentValidation." In that case you must register it manually (see issue 97 for more details):

services.TryAddTransient<IValidatorFactory, ServiceProviderValidatorFactory>();
services.AddFluentValidationRulesToSwagger();

Problem: Newtonsoft.Json DefaultNamingStrategy, SnakeCaseNamingStrategy does not work


Startup.cs:

    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.PropertyNamingPolicy = new NewtonsoftJsonNamingPolicy(new SnakeCaseNamingStrategy());
        //options.JsonSerializerOptions.DictionaryKeyPolicy = new NewtonsoftJsonNamingPolicy(new SnakeCaseNamingStrategy());
    })


    /// <summary>
    /// Allows use Newtonsoft <see cref="NamingStrategy"/> as System.Text <see cref="JsonNamingPolicy"/>.
    /// </summary>
    public class NewtonsoftJsonNamingPolicy : JsonNamingPolicy
    {
        private readonly NamingStrategy _namingStrategy;

        /// <summary>
        /// Creates new instance of <see cref="NewtonsoftJsonNamingPolicy"/>.
        /// </summary>
        /// <param name="namingStrategy">Newtonsoft naming strategy.</param>
        public NewtonsoftJsonNamingPolicy(NamingStrategy namingStrategy)
        {
            _namingStrategy = namingStrategy;
        }

        /// <inheritdoc />
        public override string ConvertName(string name)
        {
            return _namingStrategy.GetPropertyName(name, false);
        }
    }

Credits

Initial version of this project was based on Mujahid Daud Khan answer on StackOverflow: https://stackoverflow.com/questions/44638195/fluent-validation-with-swagger-in-asp-net-core/49477995#49477995

Changes in 0.0.2:

  • Added FluentValidationRulesRegistrator

Changes in 0.0.1:

  • Added FluentValidationRules.

Full release notes can be found at https://github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation/blob/master/CHANGELOG.md

  • .NETStandard 2.0
    • FluentValidation (>= 7.2.0)
    • Swashbuckle.AspNetCore (>= 1.1.0)
  • .NETStandard 2.0: 2.0.0.0

Owners

avgalex Alexey Petryashev

Authors

alexey.petriashev, MicroElements

Project URL

https://github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation

License

MIT

Tags

swagger swashbuckle FluentValidation aspnetcore

Info

5588 total downloads
74 downloads for version 0.0.2
Download (6.73 KB)
Found on the current feed only

Package history

Version Size Last updated Downloads Mirrored?
7.0.1 134.52 KB Mon, 08 Dec 2025 07:47:11 GMT 2
7.0.0 130.87 KB Sun, 07 Dec 2025 19:21:58 GMT 18
6.1.1 83.14 KB Mon, 01 Sep 2025 08:29:13 GMT 51
6.1.0 83.15 KB Mon, 01 Sep 2025 07:36:07 GMT 70
6.0.0 38.37 KB Sat, 23 Dec 2023 19:44:23 GMT 85
6.0.0-beta.3 38.37 KB Mon, 01 May 2023 13:55:43 GMT 69
6.0.0-beta.2 38.7 KB Sun, 12 Feb 2023 20:28:39 GMT 82
6.0.0-beta.1 39.05 KB Sat, 23 Jul 2022 20:03:41 GMT 83
5.7.0 43.32 KB Fri, 10 Jun 2022 10:38:09 GMT 78
5.6.0 43.32 KB Fri, 10 Jun 2022 10:24:11 GMT 73
5.5.0 43.38 KB Sun, 01 May 2022 19:40:08 GMT 76
5.4.0 43.58 KB Mon, 28 Mar 2022 18:35:16 GMT 81
5.3.0 43.57 KB Sun, 19 Sep 2021 15:22:18 GMT 75
5.2.0 43.48 KB Sat, 31 Jul 2021 14:50:34 GMT 83
5.1.0 43.46 KB Thu, 17 Jun 2021 15:59:54 GMT 83
5.1.0-rc.2 43.47 KB Thu, 03 Jun 2021 20:35:12 GMT 84
5.1.0-rc.1 42.49 KB Tue, 01 Jun 2021 08:14:50 GMT 82
5.0.0 41.65 KB Sun, 30 May 2021 09:25:09 GMT 80
5.0.0-rc.2 41.67 KB Tue, 18 May 2021 14:25:52 GMT 79
5.0.0-rc.1 41.64 KB Tue, 18 May 2021 10:35:39 GMT 74
4.3.0 28.73 KB Sun, 02 May 2021 18:37:25 GMT 85
4.3.0-rc.1 29.02 KB Thu, 25 Mar 2021 16:20:24 GMT 84
4.2.0 28.92 KB Sun, 21 Mar 2021 14:21:00 GMT 74
4.1.0 26.27 KB Thu, 18 Feb 2021 19:18:07 GMT 81
4.1.0-rc.1 26.28 KB Fri, 08 Jan 2021 14:04:28 GMT 79
4.0.0 23.81 KB Fri, 01 Jan 2021 18:15:58 GMT 80
4.0.0-rc.2 22.58 KB Sat, 18 Jul 2020 11:34:07 GMT 81
4.0.0-rc.1 22.91 KB Mon, 15 Jun 2020 07:44:40 GMT 87
3.2.0 22.43 KB Thu, 16 Jul 2020 08:55:46 GMT 81
3.1.1 21.06 KB Tue, 28 Apr 2020 19:50:38 GMT 77
3.1.0 21.08 KB Tue, 28 Apr 2020 19:44:12 GMT 69
3.0.0 21 KB Fri, 06 Mar 2020 18:33:53 GMT 83
3.0.0-rc.6 20.78 KB Wed, 05 Feb 2020 19:14:35 GMT 81
3.0.0-rc.5 20.83 KB Fri, 24 Jan 2020 16:14:36 GMT 89
3.0.0-rc.4 19.93 KB Sun, 29 Dec 2019 21:20:26 GMT 74
3.0.0-rc.3 18.63 KB Thu, 28 Nov 2019 20:13:09 GMT 83
3.0.0-rc.2 18.46 KB Sun, 13 Oct 2019 19:01:50 GMT 77
3.0.0-rc.1 18.29 KB Mon, 30 Sep 2019 21:32:44 GMT 73
3.0.0-beta.1 18.08 KB Thu, 25 Apr 2019 21:47:21 GMT 95
3.0.0-alpha.1 17.97 KB Tue, 23 Apr 2019 20:36:02 GMT 81
2.3.0 18.92 KB Thu, 14 Nov 2019 20:19:50 GMT 85
2.2.1 18.67 KB Thu, 14 Nov 2019 19:23:42 GMT 80
2.2.0 18.3 KB Wed, 28 Aug 2019 20:28:53 GMT 90
2.1.1 17.83 KB Thu, 25 Apr 2019 21:48:11 GMT 82
2.1.0 17.73 KB Mon, 08 Apr 2019 12:24:34 GMT 64
2.0.1 17.79 KB Mon, 08 Apr 2019 12:06:38 GMT 73
2.0.0 16.5 KB Wed, 13 Mar 2019 19:08:14 GMT 98
2.0.0-beta.5 16.29 KB Sun, 24 Feb 2019 07:31:07 GMT 82
2.0.0-beta.4 16.31 KB Wed, 13 Feb 2019 20:13:52 GMT 75
2.0.0-beta.3 16.36 KB Mon, 11 Feb 2019 20:23:30 GMT 82
2.0.0-beta.2 16.81 KB Mon, 21 Jan 2019 20:37:24 GMT 76
2.0.0-beta.1 16.76 KB Mon, 12 Nov 2018 20:40:04 GMT 88
1.2.0 16.09 KB Tue, 22 Jan 2019 07:33:31 GMT 78
1.1.0 16.1 KB Mon, 21 Jan 2019 22:00:43 GMT 85
1.0.0 16.5 KB Wed, 26 Sep 2018 20:08:53 GMT 89
1.0.0-rc.1 16.52 KB Fri, 21 Sep 2018 20:37:01 GMT 80
1.0.0-beta.3 16.5 KB Wed, 19 Sep 2018 19:48:11 GMT 88
1.0.0-beta.2 15.93 KB Mon, 10 Sep 2018 16:27:12 GMT 75
1.0.0-beta.1 14.27 KB Fri, 24 Aug 2018 17:32:30 GMT 77
0.8.2 14.05 KB Fri, 29 Jun 2018 09:29:45 GMT 73
0.8.1 14.02 KB Wed, 20 Jun 2018 23:33:00 GMT 74
0.8.0 13.96 KB Tue, 12 Jun 2018 22:26:34 GMT 86
0.8.0-beta.3 13.97 KB Tue, 12 Jun 2018 22:21:17 GMT 83
0.8.0-beta.2 13.83 KB Mon, 11 Jun 2018 10:57:57 GMT 71
0.8.0-beta.1 13.24 KB Fri, 11 May 2018 10:39:26 GMT 82
0.7.0 13.1 KB Fri, 11 May 2018 10:24:33 GMT 79
0.6.0 10.27 KB Wed, 04 Apr 2018 19:32:20 GMT 78
0.5.0 10.24 KB Fri, 30 Mar 2018 20:04:37 GMT 71
0.4.0 9.81 KB Thu, 29 Mar 2018 23:07:36 GMT 83
0.3.0 8.46 KB Thu, 29 Mar 2018 21:28:37 GMT 80
0.2.0 6.73 KB Sun, 25 Mar 2018 15:14:15 GMT 85
0.0.2 6.73 KB Fri, 23 Mar 2018 20:19:30 GMT 74