从验证器覆盖http状态代码

时间:2014-03-31 12:41:01

标签: c# servicestack http-status-codes fluentvalidation

我有以下DTO:

public class SomethingRequest {
     public string Code { get; set; }
}

Code必须是唯一的,因此我创建了一个验证程序,用于检查是否已有提供代码的记录,如下所示

public class SomethingValidator: AbstractValidator<SomethingRequest> 
{
    public SomethingValidator(ISomethingRepository repo) {
         RuleFor(something => something.Code).Must(BeUnique);
    }

    private bool BeUnique(string code) { ... uniqueness check... }
}

由于我使用验证功能,验证器会自动连接到SomethingRequest的所有方法,这真的很棒。

当条件失败时,我想返回409 Conflict HTTP状态代码,但始终会返回400 Bad Request

所以,问题是:

  1. 我是否误用了vaidation功能? (即自动验证的验证器不能用于应用程序逻辑检查)
  2. 如果我没有,有没有办法覆盖验证工具的400 BadRequest状态代码?

2 个答案:

答案 0 :(得分:3)

1)虽然它允许依赖注入和存储库连接,但是流畅的验证代码不是你应该放置这种代码的地方,因为它更符合验证代码。 This answer对两者之间的差异有一个很好的解释。我只想补充说,如果只是为了更容易返回适当的状态代码,将验证从验证中分离出来也是有意义的。

2)如果您想覆盖400 BadRequest状态代码,可以使用验证功能ErrorResponseFilter,如下所示:

Plugins.Add(new ValidationFeature
{
    ErrorResponseFilter = CustomValidationError
});

...

private object CustomValidationError(ValidationResult validationResult, object errorDto)
{
    var firstError = validationResult.Errors.First();
    return new HttpError(HttpStatusCode.Conflict, firstError.ErrorCode, firstError.ErrorMessage);
}

此过滤器看起来适用于全局解决方案,因为它似乎没有为您提供任何简单的方法来确定错误来自的dto /服务。我建议改为1改变。

答案 1 :(得分:2)

  

我是否滥用了验证功能? (即自动验证的验证器不能用于应用程序逻辑检查)

我认为这最好在远离验证的业务逻辑中完成,因为检查唯一性实际上是验证检查而不是验证,因为它需要检查数据源。 My answer on this question解决了类似问题。

虽然您可以使用ErrorResponseFilter覆盖验证错误的响应状态代码,但我建议您为此业务逻辑创建自己的请求过滤器,因为覆盖响应会随着应用程序的增长而变得混乱,并且再次,它不是真正的验证。

在ServiceStack中使用过滤器属性很简单:

public class VerifySomethingCodeAttribute : Attribute, IHasRequestFilter
{
    IHasRequestFilter IHasRequestFilter.Copy()
    {
        return this;
    }

    public int Priority { get { return int.MinValue; } }

    public void RequestFilter(IRequest req, IResponse res, object requestDto)
    {
        SomethingRequest somethingRequestDto = requestDto as SomethingRequest;
        if(somethingRequestDto == null)
            return;

        // Verify the code
        // Replace with suitable logic
        // If you need the database your wire it up from the IoC
        // i.e. HostContext.TryResolve<IDbConnectionFactory>();
        bool isUnique = ...

        if(!isUnique)
            throw HttpError.Conflict("This record already exists");
    }
}

然后只需注释DTO:

[VerifySomethingCode]
public class SomethingRequest {
    public string Code { get; set; }
}

然后,您可以确定DTO中的代码已经过验证,并且您可以返回所需的任何状态和响应。过滤器为您提供全面控制。

希望这有帮助。