17

リクエスト DTO の自動検証を処理するために、ServiceStack で FluentValidation を評価しています。

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

エラーはErrorResponseDTO をシリアル化することによってクライアントに返され、次のようになります。

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

アップデート:

ソースコードをさらに掘り下げた後、これは、より具体的にはそれが登録するリクエストフィルターに焼き付けられているようです: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);
    }
}

カスタム検証機能を作成することで、目的の効果を得ることができました。しかし、もっとエレガントな方法があるのではないでしょうか?

4

1 に答える 1