如何使用 FluentValidation .net 6 抛出异常?

发布于 2025-01-13 04:57:32 字数 2147 浏览 1 评论 0原文

我将我的 Web api 从 asp net core 3.1 迁移到 .net 6,并且在使用 FluentValidation 库时遇到了一些问题。

RuleFor(x => x.Name)
            .NotEmpty()
            .OnFailure(x =>
            {
                var message = "El nombre del Usuario es requerido.";
                throw new HttpException(message, message, (int)HttpStatusCode.BadRequest);
            })
            .Length(1, 150)
            .OnFailure(x =>
            {
                var message = "El nombre del Usuario debe contener hasta máximo 150 caracteres.";
                throw new HttpException(message, message, (int)HttpStatusCode.BadRequest);
            });

该代码过去可以正常工作,但是当我更新库时,方法 .OnFailure() 已被弃用。

我想知道如何像我以前那样为每个 OnFailure 抛出自定义异常,其中 HttpException 是继承自 Exception 的自定义类。 json 结果的示例为:

    {
  "developerMessage": "El nombre del Usuario es requerido..",
  "userMessage": "El nombre del Usuario es requerido.",
  "errorCode": 400,
  "moreInfo": ""
   }

更新

我关注了这篇文章 https://www.tutorialspoint.com/what-is-use-of- Fluent-validation-in-chash-and-how-to-use-in-chash。我使用 CascadeMode.Stop 因为前一个已被弃用,但是当我尝试测试 .Lenght 验证时,结果变量显示每个 RuleFor() 的第一个错误。我的意思是:如果我有 3 个 RuleFor() 并且每个规则有 2 个验证器,则结果变量显示每个 RuleFor() 的第一个错误消息的验证器,并且没有真正失败的错误消息。

我该如何解决这个问题?

public UserValidator()
{
  RuleFor(x => x.Name)
                .Cascade(CascadeMode.Stop)
                .NotEmpty().WithMessage("El nombre del Usuario es requerido.")
                .Length(1, 150).WithMessage("El nombre del Usuario debe contener hasta máximo 150 caracteres.");

  var result = Validate(new User()); //I need to get the context (user) to validate it , **not new User()**
        if(!result.IsValid)
        {
            foreach(var error in result.Errors)
            {
                var message = $"{error.ErrorMessage}";
                throw new HttpException(message, message, (int)HttpStatusCode.BadRequest);
            }
        }
}

I migrated my web api from asp net core 3.1 to .net 6 and I'm having some issues with the using FluentValidation library.

RuleFor(x => x.Name)
            .NotEmpty()
            .OnFailure(x =>
            {
                var message = "El nombre del Usuario es requerido.";
                throw new HttpException(message, message, (int)HttpStatusCode.BadRequest);
            })
            .Length(1, 150)
            .OnFailure(x =>
            {
                var message = "El nombre del Usuario debe contener hasta máximo 150 caracteres.";
                throw new HttpException(message, message, (int)HttpStatusCode.BadRequest);
            });

This code used to work correctly but, when I updated the library , the method .OnFailure() is deprecated.

I would like to know how can I throw a custom exception for each OnFailure as I used to do it, where HttpException is a custom class that inherited from Exception. An example of json result would be:

    {
  "developerMessage": "El nombre del Usuario es requerido..",
  "userMessage": "El nombre del Usuario es requerido.",
  "errorCode": 400,
  "moreInfo": ""
   }

UPDATED!

I followed this article https://www.tutorialspoint.com/what-is-use-of-fluent-validation-in-chash-and-how-to-use-in-chash. I used CascadeMode.Stop because the previous one is deprecated but, when I try testing .Lenght validation, the result variable shows the firt error of each RuleFor(). I mean: If I have 3 RuleFor() and each rule has 2 validators, the result variable shows the first error message's validator of each RuleFor() and no error message of the real failure.

How can I solve this?

public UserValidator()
{
  RuleFor(x => x.Name)
                .Cascade(CascadeMode.Stop)
                .NotEmpty().WithMessage("El nombre del Usuario es requerido.")
                .Length(1, 150).WithMessage("El nombre del Usuario debe contener hasta máximo 150 caracteres.");

  var result = Validate(new User()); //I need to get the context (user) to validate it , **not new User()**
        if(!result.IsValid)
        {
            foreach(var error in result.Errors)
            {
                var message = 
quot;{error.ErrorMessage}";
                throw new HttpException(message, message, (int)HttpStatusCode.BadRequest);
            }
        }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

愁以何悠 2025-01-20 04:57:32

您可以使用验证类的 ValidateAndThrow 方法,该方法是从 AbstractValidator 类继承而来的。

在您的情况下,当您想要抛出 HttpException 异常时,您必须重写验证类的 RaiseValidationException 方法,以便它们可以抛出所需的异常。

有两种方法可以做到这一点:

1 - 重写每个验证类的 RaiseValidationException 方法:

public class UserValidator : AbstractValidator<User>
{
    public UserValidator()
    {
        RuleFor(x => x.Name)
            .Cascade(CascadeMode.Stop)
            .NotEmpty()
            .WithMessage("El nombre del Usuario es requerido.")
            .Length(1, 150)
            .WithMessage("El nombre del Usuario debe contener hasta máximo 150 caracteres.");
    }

    // Add this override on your validation class
    protected override void RaiseValidationException(ValidationContext<User> context, ValidationResult result)
    {
        var firstError = result.Errors[0];

        var ex = new HttpExcpetion(firstError.ErrorMessage, (int)HttpStatusCode.BadRequest);

        throw ex;
    }
}

2 - 创建一个具有重写方法的抽象类,以便无需重新实现每个验证类:

public abstract class CustomAbstractValidator<T> : AbstractValidator<T>
{
    protected override void RaiseValidationException(ValidationContext<T> context, ValidationResult result)
    {
        var firstError = result.Errors[0];

        var ex = new HttpExcpetion(firstError.ErrorMessage, (int)HttpStatusCode.BadRequest);

        throw ex;
    }
}

public class UserValidator : CustomAbstractValidator<User>
{
    public UserValidator()
    {
        RuleFor(x => x.Name)
            .Cascade(CascadeMode.Stop)
            .NotEmpty()
            .WithMessage("El nombre del Usuario es requerido.")
            .Length(1, 150)
            .WithMessage("El nombre del Usuario debe contener hasta máximo 150 caracteres.");
    }
}

实现后,只需获取验证器实例并调用 ValidateAndThrow 方法:

1 - 不使用依赖注入:

public class YourProgramFlowClass
{
    public void YourMethod()
    {
        // ... before validation code

        var validator = new UserValidator();

        validator.ValidateAndThrow(user);

        // ... after validation code
    }
}

2 - 不使用依赖注入:

public class YourProgramFlowClass
{
    private readonly IValidator<ClassToValidate> _validator;

    public YourProgramFlowClass(IValidator<ClassToValidate> validator)
    {
        _validator = validator;
    }

    public void YourMethod()
    {
        // ... before validation code

        _validator.ValidateAndThrow(user);

        // ... after validation code
    }
}

You can use the ValidateAndThrow method of your validation class that comes by inheriting from the AbstractValidator<T> class.

In your case, as you want to throw the HttpException exception, you must override the RaiseValidationException method of your validation classes so that they can throw the desired exception.

There are two ways to do this:

1 - Overriding the RaiseValidationException method for each validation class:

public class UserValidator : AbstractValidator<User>
{
    public UserValidator()
    {
        RuleFor(x => x.Name)
            .Cascade(CascadeMode.Stop)
            .NotEmpty()
            .WithMessage("El nombre del Usuario es requerido.")
            .Length(1, 150)
            .WithMessage("El nombre del Usuario debe contener hasta máximo 150 caracteres.");
    }

    // Add this override on your validation class
    protected override void RaiseValidationException(ValidationContext<User> context, ValidationResult result)
    {
        var firstError = result.Errors[0];

        var ex = new HttpExcpetion(firstError.ErrorMessage, (int)HttpStatusCode.BadRequest);

        throw ex;
    }
}

2 - Creating an abstract class with the method overriding so that there is no need to re-implement each validation class:

public abstract class CustomAbstractValidator<T> : AbstractValidator<T>
{
    protected override void RaiseValidationException(ValidationContext<T> context, ValidationResult result)
    {
        var firstError = result.Errors[0];

        var ex = new HttpExcpetion(firstError.ErrorMessage, (int)HttpStatusCode.BadRequest);

        throw ex;
    }
}

public class UserValidator : CustomAbstractValidator<User>
{
    public UserValidator()
    {
        RuleFor(x => x.Name)
            .Cascade(CascadeMode.Stop)
            .NotEmpty()
            .WithMessage("El nombre del Usuario es requerido.")
            .Length(1, 150)
            .WithMessage("El nombre del Usuario debe contener hasta máximo 150 caracteres.");
    }
}

After implementing it, just get your validator instance and call the ValidateAndThrow method:

1 - Without dependency injection:

public class YourProgramFlowClass
{
    public void YourMethod()
    {
        // ... before validation code

        var validator = new UserValidator();

        validator.ValidateAndThrow(user);

        // ... after validation code
    }
}

2 - Without dependency injection:

public class YourProgramFlowClass
{
    private readonly IValidator<ClassToValidate> _validator;

    public YourProgramFlowClass(IValidator<ClassToValidate> validator)
    {
        _validator = validator;
    }

    public void YourMethod()
    {
        // ... before validation code

        _validator.ValidateAndThrow(user);

        // ... after validation code
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文