{"id":13429540,"url":"https://github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation","last_synced_at":"2025-03-16T03:31:40.597Z","repository":{"id":37484478,"uuid":"125909116","full_name":"micro-elements/MicroElements.Swashbuckle.FluentValidation","owner":"micro-elements","description":"Use FluentValidation rules instead of ComponentModel attributes","archived":false,"fork":false,"pushed_at":"2023-12-23T19:43:25.000Z","size":473,"stargazers_count":380,"open_issues_count":32,"forks_count":57,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-10-29T18:46:17.452Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/micro-elements.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null},"funding":{"github":"micro-elements","open_collective":"micro-elements"}},"created_at":"2018-03-19T19:23:35.000Z","updated_at":"2024-10-16T07:48:34.000Z","dependencies_parsed_at":"2023-12-18T19:43:40.452Z","dependency_job_id":"8d89987c-4803-4a58-820f-26510e09a2bd","html_url":"https://github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation","commit_stats":{"total_commits":216,"total_committers":23,"mean_commits":9.391304347826088,"dds":0.1435185185185185,"last_synced_commit":"f0aa699f62debb9e1b96d40c94ff7b99019d9c86"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micro-elements%2FMicroElements.Swashbuckle.FluentValidation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micro-elements%2FMicroElements.Swashbuckle.FluentValidation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micro-elements%2FMicroElements.Swashbuckle.FluentValidation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/micro-elements%2FMicroElements.Swashbuckle.FluentValidation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/micro-elements","download_url":"https://codeload.github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243320064,"owners_count":20272404,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T02:00:41.474Z","updated_at":"2025-03-16T03:31:40.209Z","avatar_url":"https://github.com/micro-elements.png","language":"C#","funding_links":["https://github.com/sponsors/micro-elements","https://opencollective.com/micro-elements"],"categories":["Frameworks, Libraries and Tools","others","C\\#","C#","框架, 库和工具"],"sub_categories":["API"],"readme":"﻿# MicroElements.Swashbuckle.FluentValidation\nUse FluentValidation rules instead of ComponentModel attributes to define swagger schema.\n\nNote: For WebApi see: https://github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation.WebApi\n\n## Statuses\n\n[![License](https://img.shields.io/github/license/micro-elements/MicroElements.Swashbuckle.FluentValidation.svg)](https://raw.githubusercontent.com/micro-elements/MicroElements.Swashbuckle.FluentValidation/master/LICENSE)\n[![NuGetVersion](https://img.shields.io/nuget/v/MicroElements.Swashbuckle.FluentValidation.svg)](https://www.nuget.org/packages/MicroElements.Swashbuckle.FluentValidation)\n![NuGetDownloads](https://img.shields.io/nuget/dt/MicroElements.Swashbuckle.FluentValidation.svg)\n[![MyGetVersion](https://img.shields.io/myget/micro-elements/v/MicroElements.Swashbuckle.FluentValidation.svg)](https://www.myget.org/feed/micro-elements/package/nuget/MicroElements.Swashbuckle.FluentValidation)\n\n![Build and publish](https://github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation/workflows/Build%20and%20publish/badge.svg)\n[![AppVeyor](https://img.shields.io/appveyor/ci/micro-elements/microelements-swashbuckle-fluentvalidation.svg?logo=appveyor)](https://ci.appveyor.com/project/micro-elements/microelements-swashbuckle-fluentvalidation)\n[![Coverage Status](https://img.shields.io/coveralls/micro-elements/MicroElements.Swashbuckle.FluentValidation.svg)](https://coveralls.io/r/micro-elements/MicroElements.Swashbuckle.FluentValidation)\n\n[![Gitter](https://img.shields.io/gitter/room/micro-elements/MicroElements.Swashbuckle.FluentValidation.svg)](https://gitter.im/micro-elements/MicroElements.Swashbuckle.FluentValidation)\n\n### Supporting the project\nMicroElements.Swashbuckle.FluentValidation is developed and supported by [@petriashev](https://github.com/petriashev) for free in his spare time.\nIf you find MicroElements.Swashbuckle.FluentValidation useful, please consider financially supporting the project via [OpenCollective](https://opencollective.com/micro-elements) which will help keep the project going 🙏.\n\n## Usage\n\n### 1. Minimal API\n\n#### MinimalApi.csproj\n\n```xml\n\u003cProject Sdk=\"Microsoft.NET.Sdk.Web\"\u003e\n\n    \u003cPropertyGroup\u003e\n        \u003cTargetFramework\u003enet7.0\u003c/TargetFramework\u003e\n        \u003cNullable\u003eenable\u003c/Nullable\u003e\n        \u003cImplicitUsings\u003eenable\u003c/ImplicitUsings\u003e\n    \u003c/PropertyGroup\u003e\n\n    \u003cItemGroup\u003e\n        \u003cPackageReference Include=\"FluentValidation.AspNetCore\" Version=\"11.2.2\" /\u003e\n        \u003cPackageReference Include=\"MicroElements.Swashbuckle.FluentValidation\" Version=\"6.0.0\" /\u003e\n        \u003cPackageReference Include=\"Microsoft.AspNetCore.OpenApi\" Version=\"7.0.2\" /\u003e\n        \u003cPackageReference Include=\"Swashbuckle.AspNetCore\" Version=\"6.4.0\" /\u003e\n    \u003c/ItemGroup\u003e\n    \n\u003c/Project\u003e\n\n```\n\n#### Program.cs\n\n```csharp\nusing FluentValidation;\nusing FluentValidation.AspNetCore;\nusing MicroElements.Swashbuckle.FluentValidation.AspNetCore;\n\nvar builder = WebApplication.CreateBuilder(args);\nvar services = builder.Services;\n\n// Asp.Net stuff\nservices.AddControllers();\nservices.AddEndpointsApiExplorer();\n\n// Add Swagger\nservices.AddSwaggerGen();\n\n// Add FV\nservices.AddFluentValidationAutoValidation();\nservices.AddFluentValidationClientsideAdapters();\n\n// Add FV validators\nservices.AddValidatorsFromAssemblyContaining\u003cProgram\u003e();\n\n// Add FV Rules to swagger\nservices.AddFluentValidationRulesToSwagger();\n\nvar app = builder.Build();\n\n// Use Swagger\napp.UseSwagger();\napp.UseSwaggerUI();\n\napp.MapControllers();\n\napp.Run();\n```\n\n### 2. AspNetCore WebApi\n\n#### Reference packages in your web project\n\n```xml\n\u003cPackageReference Include=\"FluentValidation.AspNetCore\" Version=\"11.1.0\" /\u003e\n\u003cPackageReference Include=\"MicroElements.Swashbuckle.FluentValidation\" Version=\"6.0.0\" /\u003e\n\u003cPackageReference Include=\"Swashbuckle.AspNetCore\" Version=\"6.3.0\" /\u003e\n```\n\n#### Change Startup.cs\n\n```csharp\n// This method gets called by the runtime. Use this method to add services to the container.\npublic void ConfigureServices(IServiceCollection services)\n{\n    // Asp.net stuff\n    services.AddControllers();\n    \n    // HttpContextValidatorRegistry requires access to HttpContext\n    services.AddHttpContextAccessor();\n\n    // Register FV validators\n    services.AddValidatorsFromAssemblyContaining\u003cStartup\u003e(lifetime: ServiceLifetime.Scoped);\n\n    // Add FV to Asp.net\n    services.AddFluentValidationAutoValidation();\n\n    // Add swagger\n    services.AddSwaggerGen(c =\u003e\n    {\n        c.SwaggerDoc(\"v1\", new OpenApiInfo { Title = \"My API\", Version = \"v1\" });\n    });\n\n    // [Optional] Add INameResolver (SystemTextJsonNameResolver will be registered by default)\n    // services.AddSingleton\u003cINameResolver, CustomNameResolver\u003e();\n\n    // Adds FluentValidationRules staff to Swagger. (Minimal configuration)\n    services.AddFluentValidationRulesToSwagger();\n\n    // [Optional] Configure generation options for your needs. Also can be done with services.Configure\u003cSchemaGenerationOptions\u003e\n    // services.AddFluentValidationRulesToSwagger(options =\u003e\n    // {\n    //     options.SetNotNullableIfMinLengthGreaterThenZero = true;\n    //     options.UseAllOffForMultipleRules = true;\n    // });\n\n    // Adds logging\n    services.AddLogging(builder =\u003e builder.AddConsole());\n}\n\n// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.\npublic void Configure(IApplicationBuilder app, IHostingEnvironment env)\n{\n    app.UseRouting();\n\n    app.UseEndpoints(endpoints =\u003e\n    {\n        endpoints.MapControllers();\n    });\n\n    // Adds swagger\n    app.UseSwagger();\n\n    // Adds swagger UI\n    app.UseSwaggerUI(c =\u003e\n    {\n        c.SwaggerEndpoint(\"/swagger/v1/swagger.json\", \"My API V1\");\n    });\n}\n```\n\n## Version compatibility\n\n| MicroElements.Swashbuckle.FluentValidation | Swashbuckle.AspNetCore | FluentValidation |\n|--------------------------------------------|------------------------|------------------|\n| [1.1.0, 2.0.0)                             | [3.0.0, 4.0.0)         | \u003e=7.2.0          |\n| [2.0.0, 3.0.0)                             | [4.0.0, 5.0.0)         | \u003e=8.1.3          |\n| [3.0.0, 3.1.0)                             | [5.0.0, 5.2.0)         | \u003e=8.3.0          |\n| [3.1.0, 4.2.1)                             | [5.2.0, 6.0.0)         | \u003e=8.3.0          |\n| [4.2.0, 5.0.0)                             | [5.5.1, 7.0.0)         | [9.0.0, 10)      |\n| [5.0.0, 6.0.0)                             | [6.3.0, 7.0.0)         | [10.0.0, 12)     |\n\n## Sample application\n\nSee sample project: https://github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation/tree/master/samples/SampleWebApi\n\n## Supported validators\n\n* INotNullValidator (NotNull)\n* INotEmptyValidator (NotEmpty)\n* ILengthValidator (for strings: Length, MinimumLength, MaximumLength, ExactLength) (for arrays: MinItems, MaxItems)\n* IRegularExpressionValidator (Email, Matches)\n* IComparisonValidator (GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqual)\n* IBetweenValidator (InclusiveBetween, ExclusiveBetween)\n\n## Extensibility\n\nYou can register FluentValidationRule in ServiceCollection.\n\nUser defined rule name replaces default rule with the same.\nFull list of default rules can be get by `FluentValidationRules.CreateDefaultRules()`\n\nList or default rules:\n\n* Required\n* NotEmpty\n* Length\n* Pattern\n* Comparison\n* Between\n\nExample of rule:\n\n```csharp\nnew FluentValidationRule(\"Pattern\")\n{\n    Matches = propertyValidator =\u003e propertyValidator is IRegularExpressionValidator,\n    Apply = context =\u003e\n    {\n        var regularExpressionValidator = (IRegularExpressionValidator)context.PropertyValidator;\n        context.Schema.Properties[context.PropertyKey].Pattern = regularExpressionValidator.Expression;\n    }\n},\n```\n\n## Samples\n\n### Swagger Sample model and validator\n\n```csharp\npublic class Sample\n{\n    public string PropertyWithNoRules { get; set; }\n\n    public string NotNull { get; set; }\n    public string NotEmpty { get; set; }\n    public string EmailAddress { get; set; }\n    public string RegexField { get; set; }\n\n    public int ValueInRange { get; set; }\n    public int ValueInRangeExclusive { get; set; }\n\n    public float ValueInRangeFloat { get; set; }\n    public double ValueInRangeDouble { get; set; }\n}\n\npublic class SampleValidator : AbstractValidator\u003cSample\u003e\n{\n    public SampleValidator()\n    {\n        RuleFor(sample =\u003e sample.NotNull).NotNull();\n        RuleFor(sample =\u003e sample.NotEmpty).NotEmpty();\n        RuleFor(sample =\u003e sample.EmailAddress).EmailAddress();\n        RuleFor(sample =\u003e sample.RegexField).Matches(@\"(\\d{4})-(\\d{2})-(\\d{2})\");\n\n        RuleFor(sample =\u003e sample.ValueInRange).GreaterThanOrEqualTo(5).LessThanOrEqualTo(10);\n        RuleFor(sample =\u003e sample.ValueInRangeExclusive).GreaterThan(5).LessThan(10);\n\n        // WARNING: Swashbuckle implements minimum and maximim as int so you will loss fraction part of float and double numbers\n        RuleFor(sample =\u003e sample.ValueInRangeFloat).InclusiveBetween(1.1f, 5.3f);\n        RuleFor(sample =\u003e sample.ValueInRangeDouble).ExclusiveBetween(2.2, 7.5f);\n    }\n}\n```\n\n### Swagger Sample model screenshot\n\n![SwaggerSample](image/swagger_sample.png \"SwaggerSample\")\n\n### Validator with Include\n\n```csharp\npublic class CustomerValidator : AbstractValidator\u003cCustomer\u003e\n{\n    public CustomerValidator()\n    {\n        RuleFor(customer =\u003e customer.Surname).NotEmpty();\n        RuleFor(customer =\u003e customer.Forename).NotEmpty().WithMessage(\"Please specify a first name\");\n\n        Include(new CustomerAddressValidator());\n    }\n}\n\ninternal class CustomerAddressValidator : AbstractValidator\u003cCustomer\u003e\n{\n    public CustomerAddressValidator()\n    {\n        RuleFor(customer =\u003e customer.Address).Length(20, 250);\n    }\n}\n```\n\n## Get params bounded to validatable models\n\nMicroElements.Swashbuckle.FluentValidation updates swagger schema for operation parameters bounded to validatable models.\n\n## Defining rules dynamically from database\n\nSee BlogValidator in sample.\n\n## Common problems and workarounds\n\n### Error: `System.InvalidOperationException: 'Cannot resolve 'IValidator\u003cT\u003e' from root provider because it requires scoped service 'TDependency'`\n\nWorkarounds in order or preference:\n\n#### Workaround 1 (Use HttpContextServiceProviderValidatorFactory) by @WarpSpideR\n\n```csharp\npublic void ConfigureServices(IServiceCollection services)\n{\n    // HttpContextServiceProviderValidatorFactory requires access to HttpContext\n    services.AddHttpContextAccessor();\n\n    services\n        .AddMvc()\n        // Adds fluent validators to Asp.net\n        .AddFluentValidation(c =\u003e\n        {\n            c.RegisterValidatorsFromAssemblyContaining\u003cStartup\u003e();\n            // Optionally set validator factory if you have problems with scope resolve inside validators.\n            c.ValidatorFactoryType = typeof(HttpContextServiceProviderValidatorFactory);\n        });\n```\n\n#### Workaround 2 (Use ScopedSwaggerMiddleware)\n\nReplace `UseSwagger` for `UseScopedSwagger`:\n\n```csharp\npublic void Configure(IApplicationBuilder app, IHostingEnvironment env)\n{\n    app\n        .UseMvc()\n        // Use scoped swagger if you have problems with scoped services in validators\n        .UseScopedSwagger();\n```\n\n#### Workaround 3 (Set ValidateScopes to false)\n\n```csharp\npublic static IWebHost BuildWebHost(string[] args) =\u003e\n    WebHost.CreateDefaultBuilder(args)\n        // Needed for using scoped services (for example DbContext) in validators\n        .UseDefaultServiceProvider(options =\u003e options.ValidateScopes = false)\n        .UseStartup\u003cStartup\u003e()\n        .Build();\n```\n\n## Problem: I cant use several validators of one type\n\nExample: You split validator into several small validators but AspNetCore uses only one of them.\n\nWorkaround: Hide dependent validators with `internal` and use `Include` to include other validation rules to one \"Main\" validator.\n\n\n## Problem: I'm using `FluentValidation` or `FluentValidation.DependencyInjectionExtensions` instead of `FluentValidation.AspNetCore`\n\nIf 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](https://github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation/issues/97) for more details):\n````cs\nservices.TryAddTransient\u003cIValidatorFactory, ServiceProviderValidatorFactory\u003e();\nservices.AddFluentValidationRulesToSwagger();\n````\n\n## Problem: Newtonsoft.Json DefaultNamingStrategy, SnakeCaseNamingStrategy does not work\n\n```csharp\n\nStartup.cs:\n\n    .AddJsonOptions(options =\u003e\n    {\n        options.JsonSerializerOptions.PropertyNamingPolicy = new NewtonsoftJsonNamingPolicy(new SnakeCaseNamingStrategy());\n        //options.JsonSerializerOptions.DictionaryKeyPolicy = new NewtonsoftJsonNamingPolicy(new SnakeCaseNamingStrategy());\n    })\n\n\n    /// \u003csummary\u003e\n    /// Allows use Newtonsoft \u003csee cref=\"NamingStrategy\"/\u003e as System.Text \u003csee cref=\"JsonNamingPolicy\"/\u003e.\n    /// \u003c/summary\u003e\n    public class NewtonsoftJsonNamingPolicy : JsonNamingPolicy\n    {\n        private readonly NamingStrategy _namingStrategy;\n\n        /// \u003csummary\u003e\n        /// Creates new instance of \u003csee cref=\"NewtonsoftJsonNamingPolicy\"/\u003e.\n        /// \u003c/summary\u003e\n        /// \u003cparam name=\"namingStrategy\"\u003eNewtonsoft naming strategy.\u003c/param\u003e\n        public NewtonsoftJsonNamingPolicy(NamingStrategy namingStrategy)\n        {\n            _namingStrategy = namingStrategy;\n        }\n\n        /// \u003cinheritdoc /\u003e\n        public override string ConvertName(string name)\n        {\n            return _namingStrategy.GetPropertyName(name, false);\n        }\n    }\n```\n\n## Credits\n\nInitial version of this project was based on\n[Mujahid Daud Khan](https://stackoverflow.com/users/1735196/mujahid-daud-khan) answer on StackOverflow:\nhttps://stackoverflow.com/questions/44638195/fluent-validation-with-swagger-in-asp-net-core/49477995#49477995\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicro-elements%2FMicroElements.Swashbuckle.FluentValidation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmicro-elements%2FMicroElements.Swashbuckle.FluentValidation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicro-elements%2FMicroElements.Swashbuckle.FluentValidation/lists"}