RequestFilterを使用するだけでは不十分な理由については説明していません。https://github.com/ServiceStack/ServiceStack/wiki/Validationで説明されているように、AppHost.Configure()でこれを行います。
// Enable the validation feature
Plugins.Add(new ValidationFeature());
// This method scans the assembly for validators
container.RegisterValidators(Assemblies);
これにより、検証用のRequestFilterが設定され、指定されたアセンブリで定義されたすべてのバリデーターが登録されます。検証エラーが見つかった場合、RequestFilterにより、サービスを呼び出す代わりに例外がスローされます。
あなたがしているすべての配線は、ServiceStackがあなたのためにできることと比較して、私には冗長(そしてもろい)に見えます。
とはいえ、リクエスト後の検証に従えば、私はそうしません。リクエストが無効な場合は実行できないことを保証するのではなく、サービスが無効な結果を返さないことを保証しようとしていると思います。これは、データリポジトリを信頼しておらず、完全に失敗し、不良データを表示することさえできない(消費者が修正するのが困難になる可能性がある)という、私にとってはちょっとしたケースのように思えます。
また、応答フィルターはまだ使用していないので、どのような制限があるのかわかりません。しかし、https://github.com/ServiceStack/ServiceStack/wiki/Request-and-response-filtersを見ると、ほぼ同じことができることが示されているようです...したがって、別の応答を記述できるようです。応答ストリームを実行してから閉じます。これは、応答フィルターがサービスの後、応答ストリームへのシリアル化が発生する前に実行されることを意味します。したがって、別の応答を書き出すことができるはずであり、サービスの応答は無視されます。ServiceStackRequestFilterからサービスを見つける方法に投稿したコードスニペットが役立つ場合があります。
検証から返すエラーがある場合は、実行しているのと同じように、例外をスローするか、エラー応答を直接書き込むことができます。ただし、ServiceStackによって提供されるコードを見てください。プロジェクトをダウンロードし、ValidationFilter.csのRequestFilterコードを借用/変更します。これが役立つ場合の現在の実装は次のとおりです。
public void RequestFilter(IHttpRequest req, IHttpResponse res, object requestDto)
{
IValidator validator = ValidatorCache.GetValidator(req, requestDto.GetType());
if (validator == null)
return;
IRequiresHttpRequest requiresHttpRequest = validator as IRequiresHttpRequest;
if (requiresHttpRequest != null)
requiresHttpRequest.HttpRequest = req;
string httpMethod = req.HttpMethod;
ValidationResult result = validator.Validate(new ValidationContext(requestDto, (PropertyChain) null, (IValidatorSelector) new MultiRuleSetValidatorSelector(new string[1]
{
httpMethod
})));
if (result.IsValid)
return;
object errorResponse = DtoUtils.CreateErrorResponse(requestDto, ValidationResultExtensions.ToErrorResult(result));
ServiceStack.WebHost.Endpoints.Extensions.HttpResponseExtensions.WriteToResponse(res, req, errorResponse);
}
応答フィルターは要求フィルターに似ているはずですが、独自にインストールする必要があります。これを行うには、独自のIPluginを実装する必要があります。これを行う簡単な方法の1つは、既存のValidationFeature.csをhttps://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack.ServiceInterface/Validation/ValidationFeature.csからコピー/貼り付け/編集することです。(クラスにはいくつかのプライベート要素があり、サブクラス化には最適ではありません。そうでない場合は、それを提案します。)
必要な重要な変更は、独自のフィルターを登録することです。
/// <summary>
/// Activate the validation mechanism, so every request DTO with an existing validator
/// will be validated.
/// </summary>
/// <param name="appHost">The app host</param>
public void Register(IAppHost appHost)
{
if (Enabled) return;
Enabled = true;
// use my class instead of ServiceStack.ServiceInterface.Validation.ValidationFilters
var filter = new MyValidationFilters();
appHost.RequestFilters.Add(filter.RequestFilter);
appHost.ResponseFilters.Add(filter.RequestFilter);
}
次に、独自のMyValidationFiltersクラスを作成できます。ここでは、必要に応じてServiceStack.ServiceInterface.Validation.ValidationFiltersから派生し、それが機能する場合はRequestFilterを使用できます。ただし、ResponseFilterはRequestDTOではなくResponseDTOに渡されるため、RequestFilterとは微妙に異なる必要がある場合があります。RequestFilterからの次のスニペットに注意してください。
object errorResponse = DtoUtils.CreateErrorResponse(requestDto, ValidationResultExtensions.ToErrorResult(result));
DtoUtilsコードに示されているように、ServiceStackはrequestDtoを取得し、適切なResponse DTOを構築してデータを入力しようとするため、このコードは正しく機能しません。
public static object CreateErrorResponse(object request, ValidationErrorResult validationError)
{
ResponseStatus responseStatus = DtoUtils.ToResponseStatus(validationError);
return DtoUtils.CreateErrorResponse(request, (Exception) new ValidationError(validationError), responseStatus);
}
public static object CreateErrorResponse(object request, Exception ex, ResponseStatus responseStatus)
{
object responseDto = DtoUtils.CreateResponseDto(request, responseStatus);
IHttpError httpError = ex as IHttpError;
if (httpError != null)
{
if (responseDto != null)
httpError.Response = responseDto;
return (object) httpError;
}
else
{
string errorCode = ex.GetType().Name;
string errorMessage = ex.Message;
if (responseStatus != null)
{
errorCode = responseStatus.ErrorCode ?? errorCode;
errorMessage = responseStatus.Message ?? errorMessage;
}
return (object) new HttpError(responseDto, HttpRequestExtensions.ToStatusCode(ex), errorCode, errorMessage);
}
}
代わりに、CreateResponseDto部分をバイパスして(ResponseFilterに既にResponse DTOがあるため)、残りを実行する必要があります。
ServiceStackを変更することで、上記のすべてのコピー/貼り付けを回避できることに注意してください。重複を避けるためにServiceStackコードを自分でリファクタリングしてから、プルリクエストをgithubに送信することができます。