在Asp.net Core中使用Swagger进行流畅验证

Muj*_*han 11 fluentvalidation swagger asp.net-core

我目前正在使用Fluent Validation而不是使用Data Annotations我的Web API并使用swagger来获取API文档.流畅的验证规则没有反映在swagger模型中,因为我无法使用swagger模式过滤器配置流畅的验证规则.

本博客对ASP.net MVC使用它有很好的解释.但我无法配置它在ASP.net Core中使用它.

到目前为止,我已经尝试了以下代码,但我无法获得验证器类型.

services.AddSwaggerGen(options => options.SchemaFilter<AddFluentValidationRules>());

public class AddFluentValidationRules : ISchemaFilter
{
    public void Apply(Schema model, SchemaFilterContext context)
    {
        model.Required = new List<string>();
        var validator = GetValidator(type); // How?
        var validatorDescriptor = validator.CreateDescriptor();

        foreach (var key in model.Properties.Keys)
        {
            foreach (var propertyValidator in validatorDescriptor.GetValidatorsForMember(key))
            {
                 // Add to model properties as in blog
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Mak*_*luv 10

  1. 安装 Nuget 包:MicroElements.Swashbuckle.FluentValidation

  2. 添加到配置服务: services.AddFluentValidationRulesToSwagger();


Ale*_*hev 8

我根据Mujahid Daud Khan的回答创建了github项目和nuget包.我进行了重新设计以支持可扩展性并支持其他验证器.

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

nuget:https://www.nuget.org/packages/MicroElements.Swashbuckle.FluentValidation

注意:对于WebApi,请参阅:https://github.com/micro-elements/MicroElements.Swashbuckle.FluentValidation.WebApi

支持的验证器

  • INotNullValidator(NotNull)
  • INotEmptyValidator(NotEmpty)
  • ILengthValidator(Length,MinimumLength,MaximumLength,ExactLength)
  • IRegularExpressionValidator(电子邮件,匹配)
  • IComparisonValidator(GreaterThan,GreaterThanOrEqual,LessThan,LessThanOrEqual)
  • IBetweenValidator(InclusiveBetween,ExclusiveBetween)

用法

1.您的Web项目中的参考包:

<PackageReference Include="FluentValidation.AspNetCore" Version="7.5.2" />
<PackageReference Include="MicroElements.Swashbuckle.FluentValidation" Version="0.4.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.3.0" />
Run Code Online (Sandbox Code Playgroud)

2.更改Startup.cs

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services
        .AddMvc()
        // Adds fluent validators to Asp.net
        .AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<CustomerValidator>());

    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });
        // Adds fluent validation rules to swagger
        c.AddFluentValidationRules();
    });
}

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

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

Swagger样本模型和验证器

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 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

随意添加问题!

  • 也许你应该在你的存储库和NuGet网站上恰当地归功于Mujahid? (2认同)

Muj*_*han 7

搜索后,我终于发现我需要IValidationFactory验证器实例。

public class AddFluentValidationRules : ISchemaFilter
{
    private readonly IValidatorFactory _factory;

    /// <summary>
    ///     Default constructor with DI
    /// </summary>
    /// <param name="factory"></param>
    public AddFluentValidationRules(IValidatorFactory factory)
    {
        _factory = factory;
    }

    /// <summary>
    /// </summary>
    /// <param name="model"></param>
    /// <param name="context"></param>
    public void Apply(Schema model, SchemaFilterContext context)
    {

        // use IoC or FluentValidatorFactory to get AbstractValidator<T> instance
        var validator = _factory.GetValidator(context.SystemType);
        if (validator == null) return;
        if (model.Required == null)
            model.Required = new List<string>();

        var validatorDescriptor = validator.CreateDescriptor();
        foreach (var key in model.Properties.Keys)
        {
            foreach (var propertyValidator in validatorDescriptor
                .GetValidatorsForMember(ToPascalCase(key)))
            {
                if (propertyValidator is NotNullValidator 
                  || propertyValidator is NotEmptyValidator)
                    model.Required.Add(key);

                if (propertyValidator is LengthValidator lengthValidator)
                {
                    if (lengthValidator.Max > 0)
                        model.Properties[key].MaxLength = lengthValidator.Max;

                    model.Properties[key].MinLength = lengthValidator.Min;
                }

                if (propertyValidator is RegularExpressionValidator expressionValidator)
                    model.Properties[key].Pattern = expressionValidator.Expression;

                // Add more validation properties here;
            }
        }
    }

    /// <summary>
    ///     To convert case as swagger may be using lower camel case
    /// </summary>
    /// <param name="inputString"></param>
    /// <returns></returns>
    private static string ToPascalCase(string inputString)
    {
        // If there are 0 or 1 characters, just return the string.
        if (inputString == null) return null;
        if (inputString.Length < 2) return inputString.ToUpper();
        return inputString.Substring(0, 1).ToUpper() + inputString.Substring(1);
    }
}
Run Code Online (Sandbox Code Playgroud)

并将此类添加到 swaggerGen 选项

options.SchemaFilter<AddFluentValidationRules>();
Run Code Online (Sandbox Code Playgroud)