c# - Net Core : Enforce Required Class Members in Request API Automatically,(非空数据类型)

标签 c# .net asp.net-core .net-core data-annotations

我们有 API Controller ,它通过 Request Dto 获取产品数据。为了使类成员成为必需的,我们需要在 Dto 中放置 Required 属性。否则服务可以使用空成员执行。

https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-3.1

目前 Request DTO 有 20 多个成员,在所有类成员中编写 [Required] 看起来非常重复。

我的问题是,为什么需要RequiredAttribute?我们已经有了 int 和可为 null 的成员。数据类型本身不应该强制执行契约吗?

有没有一种方法可以自动化并让类成员强制执行必需的,而无需到处编写?

[HttpPost]
[Route("[action]")]
public async Task<ActionResult<ProductResponse>> GetProductData(BaseRequest<ProductRequestDto> request)
{
    var response = await _productService.GetProductItem(request);
    return Ok(response);


public class ProductRequestDto
{
    public int ProductId { get; set; }
    public bool Available { get; set; }
    public int BarCodeNumber{ get; set; }
    ....

How to add custom error message with “required” htmlattribute to mvc 5 razor view text input editor

public class ProductRequestDto
{
    [Required]
    public int ProductId { get; set; }

    [Required]
    public bool Available { get; set; }

    [Required]
    public int BarCodeNumber{ get; set; }
    ....

最佳答案

如果您愿意使用 Fluent Validation你可以这样做:

该验证器可以使用反射验证任何 dto

验证器:

using FluentValidation;
using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleTests
{
    public class MyValidator : AbstractValidator<ModelDTO>
    {
        public MyValidator()
        {
            foreach (var item in typeof(ModelDTO).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance))
            {
                Console.WriteLine($"Name: {item.Name}, Type: {item.PropertyType}");

                if (item.PropertyType == typeof(int))
                {
                    RuleFor(x => (int)item.GetValue(x, null)).NotEmpty<ModelDTO,int>();
                }
                else
                {
                    RuleFor(x => (string)item.GetValue(x, null)).NotEmpty<ModelDTO, string>();
                }
            //Other stuff...
            }
        }
    }
}

NotEmpty 拒绝 null 和默认值。

程序.cs

using System;
using System.ComponentModel.DataAnnotations;
using System.IO;

namespace ConsoleTests
{
    class Program
    {
        static void Main(string[] args)
        {

            try
            {
                ModelDTO modelDTO = new ModelDTO
                {
                    MyProperty1 = null, //string
                    MyProperty2 = 0, //int
                    MyProperty3 = null, //string
                    MyProperty4 = 0 //int
                };

                MyValidator validationRules = new MyValidator();
                FluentValidation.Results.ValidationResult result = validationRules.Validate(modelDTO);

                foreach (var error in result.Errors)
                {
                    Console.WriteLine(error);
                }

                Console.WriteLine("Done!");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

输出:

Name: MyProperty1, Type: System.String
Name: MyProperty2, Type: System.Int32
Name: MyProperty3, Type: System.String
Name: MyProperty4, Type: System.Int32
must not be empty.
must not be empty.
must not be empty.
must not be empty.
Done!

为了获得更完整的解决方案: 看到这个问题how-to-use-reflection-in-fluentvalidation .

它使用相同的概念,验证器采用 PropertyInfo 并通过获取类型和值来进行验证。

以下代码来自上述问题。

属性验证器:

public class CustomNotEmpty<T> : PropertyValidator
{
    private PropertyInfo _propertyInfo;

    public CustomNotEmpty(PropertyInfo propertyInfo)
        : base(string.Format("{0} is required", propertyInfo.Name))
    {
        _propertyInfo = propertyInfo;
    }

    protected override bool IsValid(PropertyValidatorContext context)
    {
        return !IsNullOrEmpty(_propertyInfo, (T)context.Instance);
    }

    private bool IsNullOrEmpty(PropertyInfo property, T obj)
    {
        var t = property.PropertyType;
        var v = property.GetValue(obj);

        // Omitted for clarity...
    }
}

规则生成器:

public static class ValidatorExtensions
{
    public static IRuleBuilderOptions<T, T> CustomNotEmpty<T>(
        this IRuleBuilder<T, T> ruleBuilder, PropertyInfo propertyInfo)
    {
        return ruleBuilder.SetValidator(new CustomNotEmpty<T>(propertyInfo));
    }
}

最后是验证器:

public class FooValidator : AbstractValidator<Foo>
{
    public FooValidator(Foo obj)
    {
        // Iterate properties using reflection
        var properties = ReflectionHelper.GetShallowPropertiesInfo(obj);//This is a custom helper that retrieves the type properties.
        foreach (var prop in properties)
        {
            // Create rule for each property, based on some data coming from other service...
            RuleFor(o => o)
                .CustomNotEmpty(obj.GetType().GetProperty(prop.Name))
                .When(o =>
            {
                return true; // do other stuff...
            });
        }
    }
}

关于c# - Net Core : Enforce Required Class Members in Request API Automatically,(非空数据类型),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63985741/

相关文章:

c# - 在 ASP.Net 5 中配置 Azure Blob 访问

c# - 如何根据每个请求更改 JsonSerializerSettings

html - Asp.Net core 3.0 'value'中的路径必须以 '/'开头

c# - 如何: solver foundation quadratic least squares

java - Web 服务与 WCF

.net - 反序列化和空引用最佳实践 - 设置为空还是忽略?

.net - MEF:标记接口(interface)用于导出

c# - 基于聚类点计数的颜色聚类特征

c# - Notifyicon 气球提示未在 C# 中显示?

c# - .NET Core 2.2 下配置中 AddJsonFile 选项的默认值是什么?