首先我应该说很棒的问题+答案丹尼尔
但是,我对其进行了更进一步的改进,对其进行了改进并添加到其中。
验证程序
我对此进行了一些细化。它现在基于泛型HttpOperationHandler
,因此可以采用HttpRequestMessage
. 这样做的原因是我可以返回使用正确媒体类型(从接受标头)格式化的错误消息。
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);
}
}
扩展方法
在方法desc
中添加 ValidationHandler 时,您提供的 2 与不再需要的参数几乎相同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”类。将其更改为使用自定义属性或您可能喜欢的任何其他方式来识别哪些类是您的“资源”并不需要太多工作。
休息验证失败
这是我制作的一个小助手类,用于允许验证失败响应的一致行为。
public class RestValidationFailure : HttpResponseMessage
{
public RestValidationFailure(string[] messages)
{
StatusCode = HttpStatusCode.BadRequest;
foreach (var errorMessage in messages)
{
Headers.Add("X-Validation-Error", errorMessage);
}
}
}
所以,现在我得到了所有验证错误的一个很好的列表(在我的首选媒体类型中)。
享受!:)