まず、素晴らしい質問と回答のダニエルを言わなければなりません
しかし、私はそれをもう少し進めて、洗練して追加しました。
検証ハンドラー
これを少し改良しました。現在はジェネリックに基づいているHttpOperationHandler
ため、HttpRequestMessage
. これは、(accept ヘッダーから) 正しいメディア タイプを使用してフォーマットされたエラー メッセージを返せるようにするためです。
public class ValidationHandler<TResource> : HttpOperationHandler<TResource, HttpRequestMessage, HttpRequestMessage>
{
public ValidationHandler() : base("response") { }
protected override HttpRequestMessage OnHandle(TResource model, HttpRequestMessage requestMessage)
{
var results = new List<ValidationResult>();
var context = new ValidationContext(model, null, null);
Validator.TryValidateObject(model, context, results, true);
if (results.Count == 0)
{
return requestMessage;
}
var errorMessages = results.Select(x => x.ErrorMessage).ToArray();
var mediaType = requestMessage.Headers.Accept.FirstOrDefault();
var response = new RestValidationFailure(errorMessages);
if (mediaType != null)
{
response.Content = new ObjectContent(typeof (string[]), errorMessages, mediaType);
}
throw new HttpResponseException(response);
}
}
拡張方法
あなたが提供した2つは、メソッドdesc
に ValidationHandler を追加するときにパラメーターが不要になったため、実質的に同じままですModelValidationFor
追加の拡張メソッドを追加しました。これは、すべての「リソース」クラスが検証されていることを確認するためです。これは主に私が怠け者で忘れっぽいことです。クラスをどこかのリストに追加するのを永遠に忘れています。(これが、一般的なウィンザー インストーラーを作成する理由です!)
public static void ValidateAllResourceTypes(this WebApiConfiguration config, string assemblyFilter = "MyCompany*.dll")
{
var path = Path.GetDirectoryName((new Uri(Assembly.GetExecutingAssembly().CodeBase)).AbsolutePath);
var dc = new DirectoryCatalog(path, assemblyFilter);
var assemblies = dc.LoadedFiles.Select(Assembly.LoadFrom).ToList();
assemblies.ForEach(assembly =>
{
var resourceTypes = assembly.GetTypes()
.Where(t => t.Namespace != null && t.Namespace.EndsWith("Resources"));
foreach (var resourceType in resourceTypes)
{
var configType = typeof(Extensions);
var mi = configType.GetMethod("ModelValidationFor");
var mi2 = mi.MakeGenericMethod(resourceType);
mi2.Invoke(null, new object[] { config });
}
});
}
このクラスにはSystem.ComponentModel.Composition.Hosting
名前空間 (以前は MEF と呼ばれていました) を使用しました。DirectoryCatalog
この場合、"Resources" で終わる名前空間を使用して "Resource" クラスを見つけました。カスタム属性を使用するように変更するか、どのクラスが「リソース」であるかを識別するために好むその他の方法を使用するように変更するのに、それほど手間はかかりません。
RestValidationFailure
これは、検証失敗応答の一貫した動作を許可するために作成した小さなヘルパー クラスです。
public class RestValidationFailure : HttpResponseMessage
{
public RestValidationFailure(string[] messages)
{
StatusCode = HttpStatusCode.BadRequest;
foreach (var errorMessage in messages)
{
Headers.Add("X-Validation-Error", errorMessage);
}
}
}
これで、すべての検証エラーの適切なリストを (好みのメディアタイプで) 取得できました。
楽しみ!:)