【问题标题】:Using Fluent Validation, in Web API project: derived classes在 Web API 项目中使用 Fluent Validation:派生类
【发布时间】:2017-08-21 16:26:36
【问题描述】:

我正在尝试在 WebApi 项目中使用“FluentValidation”实现自定义验证。

因此,在 Controller 的操作方法(POST)中,我使用基类(Person)作为参数:

[Route("persons/compute")] public HttpResponseMessage Compute(Person person)  { ... }

我从 nuget 安装了“FluentValidation 和 FluentValidation.WebApi”包。

我有以下代码:

[Serializable]   
public class Person
{        
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string CNP { get; set; } //unique identifier
}

 [Serializable]
 [Validator(typeof(StudentValidator))]
 public class Student : Person
 {
    public string CollegeName { get; set; }      
 }

验证器类是:

 public abstract class PersonValidator<T>: AbstractValidator<T> where T : Person
        {
            protected abstract PersonClassType PersonClassType { get; }
            public PersonValidator()
            {
                Custom(p => {
                    if (string.IsNullOrEmpty(p.CNP))
                    {
                        return new ValidationFailure("Insured.UniqueIdentifier", "CNP/CUI obligatoriu!");
                    }
                    else
                    {
                        decimal cnp;
                        bool isCNP = (p.CNP.Length == 13 && decimal.TryParse(p.CNP, out cnp));
                        if (!isCNP)
                        {
                            return new ValidationFailure("Insured.UniqueIdentifier", "CNP invalid!");
                        }
                    }
                    return null;
                });
            }
        }

派生类的验证器是:

public class StudentValidator : PersonValidator<Student>
    {
        public StudentValidator ()
        {
            Custom(p => {
                if (string.IsNullOrEmpty(p.CollegeName))
                {
                    return new ValidationFailure("ekfjekfj", "College Name mandatory!");
                }            

                return null;
            });
        }

        protected override PersonClassType PersonClassType
        {
            get
            {
                return PersonClassType.Student;
            }
        }
    }

 [DataContract]
    public enum PersonClassType
    {
        None = int.MinValue,
        Student = 1,
        Employee = 2
    }

在 Global.asax.cs 的 Application_Start() 中,我添加了:

 FluentValidationModelValidatorProvider.Configure(GlobalConfiguration.Configuration);

我需要什么?:在动作方法中,在控制器中,使用类型基类(Person)的参数来验证从接收到的子/派生(例如:学生、员工等)类正文(POST)。因此,它需要知道切换到正确的验证器。 我想这个问题可以使用“Factory”或“DepencyInjection”来解决,但我不知道如何。 我希望自己清楚。 我的道歉,但我的英语并不完美。

我希望有一个明确的解决方案,因为我曾尝试使用 Factory 来实现,但没有成功。如果需要,我可以发送带有我的代码的 zip 文件。 提前非常感谢!

【问题讨论】:

    标签: c# asp.net-mvc asp.net-mvc-4 asp.net-web-api fluentvalidation


    【解决方案1】:

    为了解决这个问题,我创建了以下类:

    public class ValidatorBase<TBase> : AbstractValidator<TBase>
    {
        public void MapDerivedValidator<TType, TValidatorType>()
            where TValidatorType : IEnumerable<IValidationRule>, IValidator<TType>, new()
            where TType: TBase
        {
            When(t => t.GetType() == typeof(TType), () => AddDerivedRules<TValidatorType>());
        }
    
        private void AddDerivedRules<T>()
            where T : IEnumerable<IValidationRule>, new()
        {
            IEnumerable<IValidationRule> validator = new T();
            foreach (var rule in validator)
            {
                this.AddRule(rule);
            }
        }
    }
    

    要使用它,请将您的 Person 验证器更改为从 ValidatorBase 继承(将 AbstractValidator&lt;Person&gt; 替换为 ValidatorBase&lt;Person&gt;)。

    现在,当您设置人员验证规则时,添加以下行:

    MapDerivedValidator&lt;Student, StudentValidator&gt;

    StudentValidator 可以像往常一样简单地从AbstractValidator&lt;Student&gt; 继承。


    我们在这里所做的基本上是有条件地在基类的验证器 (PersonValidator) 中包含,当被验证的类型匹配时,派生类的验证器 (StudentValidator) 的规则。

    【讨论】:

    • 感谢您的回答!
    • 现在当我尝试在真实代码中实现时,我不明白为什么验证器不起作用。我错过了什么!?示例应用程序工作正常,结构相同..
    【解决方案2】:

    为了对其他人有用,基于 Jon 解决方案的更新代码将是:

     [Route("persons/compute")]
            public HttpResponseMessage Compute([FromBody]Person person)
            {...}
    

    在 Global.asax.cs 中:

    protected void Application_Start()
            {
                GlobalConfiguration.Configure(WebApiConfig.Register);
    
                JsonSerializerSettings serializerSettings = GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings;
                serializerSettings.TypeNameHandling = TypeNameHandling.All;
                serializerSettings.TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
                serializerSettings.FloatParseHandling = FloatParseHandling.Decimal;
    
                FluentValidationModelValidatorProvider.Configure(GlobalConfiguration.Configuration);
    
            }
    

    添加类:ValidatorBase(见上文乔恩回答)

    更新 PersonValidator.cs 如下:

       public PersonValidator()
                {
                    MapDerivedValidator<Student, StudentValidator>();
                    MapDerivedValidator<Employee, EmployeeValidator>();
                    //.... other derived classes
        ...
        }
    
    
    
    public class StudentValidator : ValidatorBase<Student>
        { ...}
    

    谢谢乔恩!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-07-08
      • 2023-02-11
      • 1970-01-01
      • 1970-01-01
      • 2012-08-24
      • 2020-12-07
      • 2021-11-22
      相关资源
      最近更新 更多