在Web API项目中使用Fluent验证:派生类

时间:2017-08-21 16:26:37

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

我正在尝试使用" FluentValidation"来实现自定义验证。进入一个WebApi项目。

所以,在我的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;
                });
            }
        }

派生类的Validator是:

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);

我需要什么?:在action方法中,在控制器中,使用类型基类(Person)的参数对子项/派生(例如:学生,员工等)的classess进行验证身体(POST)。因此,需要知道切换到正确的验证器。 我想这个问题可以通过&#34; Factory&#34;来解决。或者&#34; DepencyInjection&#34;,但我不知道如何。 我希望能让自己清楚。 我的appollogize,但我的英语并不完美。

我很感激一个明确的解决方案,因为我试图用Factory实现,但我没有管理。如果需要,我可以用我的代码发送zip文件。 非常感谢提前!

2 个答案:

答案 0 :(得分: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<Person>替换为ValidatorBase<Person>)。

现在,当您为Person验证设置规则时,请添加以下行:

MapDerivedValidator<Student, StudentValidator>

StudentValidator可以像往常一样继承AbstractValidator<Student>

我们在这里做的基本上是有条件地包括在基类的验证器(PersonValidator)中来自派生类的规则&#39;验证类型匹配时验证器(StudentValidator)。

答案 1 :(得分:0)

为了对其他人有用,基于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(参见上面的Jon回答)

更新PersonValidator.cs如下:

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



public class StudentValidator : ValidatorBase<Student>
    { ...}

谢谢Jon!