2013-04-17 71 views
16

我處理請求的DTO的自動驗證評估FluentValidation in ServiceStack定製響應DTO

Plugins.Add(new ValidationFeature()); 
container.RegisterValidators(typeof(MyValidator).Assembly); 

錯誤是由序列化ErrorResponse DTO返回給客戶端,可能是這樣的:

{ 
    "ErrorCode": "GreaterThan", 
    "Message": "'Age' must be greater than '0'.", 
    "Errors": [ 
     { 
      "ErrorCode": "GreaterThan", 
      "FieldName": "Age", 
      "Message": "'Age' must be greater than '0'." 
     }, 
     { 
      "ErrorCode": "NotEmpty", 
      "FieldName": "Company", 
      "Message": "'Company' should not be empty." 
     } 
    ] 
} 

我想知道是否有可能使用不同的響應DTO返回錯誤。例如:

{ 
    "code": "123", 
    "error": "'Age' must be greater than '0'." 
} 

我知道這是可能在服務明確使用驗證:

public MyService : Service 
{ 
    private readonly IValidator<MyRequestDto> validator; 
    public MyService(IValidator<MyRequestDto> validator) 
    { 
     this.validator = validator; 
    } 

    public object Get(MyRequestDto request) 
    { 
     var result = this.validator.Validate(request); 
     if (!result.IsValid) 
     { 
      throw new SomeCustomException(result); 
     } 

     ... at this stage request DTO validation has passed 
    } 
} 

但這裏的問題是,是否有可能有這樣的驗證錯誤隱含截獲的地方所以我可以代替響應DTO,並有一個更清潔服務:

public MyService : Service 
{ 
    public object Get(MyRequestDto request) 
    { 
     ... at this stage request DTO validation has passed 
    } 
} 

UPDATE:

經過進一步挖掘到的源代碼,它看起來像,這是燒燬ValidationFeature並且更具體地,它註冊請求濾波器:

public class ValidationFilters 
{ 
    public void RequestFilter(IHttpRequest req, IHttpResponse res, object requestDto) 
    { 
     var validator = ValidatorCache.GetValidator(req, requestDto.GetType()); 
     if (validator == null) return; 

     var validatorWithHttpRequest = validator as IRequiresHttpRequest; 
     if (validatorWithHttpRequest != null) 
      validatorWithHttpRequest.HttpRequest = req; 

     var ruleSet = req.HttpMethod; 
     var validationResult = validator.Validate(
     new ValidationContext(requestDto, null, new MultiRuleSetValidatorSelector(ruleSet))); 

     if (validationResult.IsValid) return; 

     var errorResponse = DtoUtils.CreateErrorResponse(
      requestDto, validationResult.ToErrorResult()); 

     res.WriteToResponse(req, errorResponse); 
    } 
} 

通過編寫定製的驗證功能我能夠達到預期的效果。但也許有更優雅的方式?

回答

13

我只是checked in a Customization Error hook,它允許您指定一個自定義錯誤過濾器,以便在下一個版本的ServiceStack(v3.9.44 +)中更容易地支持此用例。

CustomValidationErrorTests你現在可以配置ValidationFeature使用方法,而不是返回的自定義錯誤過濾器,例如:

public override void Configure(Container container) 
{ 
    Plugins.Add(new ValidationFeature { 
     ErrorResponseFilter = CustomValidationError }); 
    container.RegisterValidators(typeof(MyValidator).Assembly);   
} 

public static object CustomValidationError(
    ValidationResult validationResult, object errorDto) 
{ 
    var firstError = validationResult.Errors[0]; 
    var dto = new MyCustomErrorDto { 
     code = firstError.ErrorCode, error = firstError.ErrorMessage }; 

    //Ensure HTTP Clients recognize this as an HTTP Error 
    return new HttpError(dto, HttpStatusCode.BadRequest, dto.code, dto.error); 
} 

現在你的HTTP客戶端將收到您的自定義錯誤響應:

try 
{ 
    var response = "http://example.org/customerror".GetJsonFromUrl(); 
} 
catch (Exception ex) 
{ 
    ex.GetResponseBody().Print(); 
    //{"code":"GreaterThan","error":"'Age' must be greater than '0'."} 
} 

警告:當以這種方式定製錯誤響應時,ServiceStack's typed C# clients將不再提供類型異常,因爲他們期望錯誤響應包含n a ResponseStatus DTO屬性。

+2

我能說什麼?奇妙!立即獲取v3.9.44 +位。 –