2013-04-17 6 views
16

Sto valutando FluentValidation in ServiceStack per gestire la validazione automatica della richiesta DTOs:risposta personalizzata DTO in ServiceStack FluentValidation

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

Gli errori vengono restituiti al client per la serializzazione di un ErrorResponse DTO e possono apparire come segue:

{ 
    "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." 
     } 
    ] 
} 

Vorrei sapere se è possibile restituire gli errori utilizzando un DTO di risposta diverso. Per esempio:

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

So che è possibile utilizzare il validatore esplicitamente al servizio:

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 
    } 
} 

Ma la domanda qui è se è possibile avere questo errore di convalida intercettato implicitamente da qualche parte in modo che posso sostituire il DTO risposta e avere un servizio più pulito:

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

UPDATE:

Dopo ulteriori scavare nel codice sorgente, sembra che questo è bruciato nella ValidationFeature e più specificamente il filtro richiesta che registra:

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

Scrivendo una funzione di validazione personalizzata Sono stato in grado di ottenere l'effetto desiderato. Ma forse c'è un modo più elegante?

risposta

13

Ho appena checked in a Customization Error hook che consente di specificare un filtro di errore personalizzato per facilitare il supporto di questo caso d'uso nella prossima versione di ServiceStack (v3.9.44 +).

Dal CustomValidationErrorTests è ora possibile configurare la ValidationFeature di utilizzare un filtro personalizzato di errore che verrà restituita al posto, ad esempio:

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

Ora i vostri clienti HTTP riceverà la vostra risposta di errore personalizzato:

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

Attenzione: Quando si personalizza la risposta di errore in questo modo ServiceStack's typed C# clients non fornirà più eccezioni digitato come si aspettano la reazione all'errore di contai n a ResponseStatus Proprietà DTO.

+2

Cosa posso dire? Meravigliosa! Ottenere subito i bit v3.9.44 +. –