C# 验证模型属性WCF Web APi
我有一组使用WCF Web Api托管的服务,我需要做的是验证应用程序模型中的属性 例如,在MVC 3中,我在模型中装饰属性,如下所示:C# 验证模型属性WCF Web APi,c#,asp.net-mvc,wcf-web-api,C#,Asp.net Mvc,Wcf Web Api,我有一组使用WCF Web Api托管的服务,我需要做的是验证应用程序模型中的属性 例如,在MVC 3中,我在模型中装饰属性,如下所示: [StringLength(30)] public string UserName { get; set; } 然后在控制器中,我按照以下步骤验证操作系统模型是否符合验证参数: [HttpPost] ActionResult Create(Model myModel) { if(ModelState.
[StringLength(30)]
public string UserName { get; set; }
然后在控制器中,我按照以下步骤验证操作系统模型是否符合验证参数:
[HttpPost]
ActionResult Create(Model myModel)
{
if(ModelState.IsValid(){
Post the model
}
else
{
Don't post the model
}
}
有没有一种方法可以在WCF Web Api中执行类似的操作?有一个例子,就是为它创建一个应该有效的行为。您还可以使用(或将其包装为扩展方法)手动调用验证器,并返回验证错误,这基本上就是该行为所做的。我目前正在处理一个HttpOperationHandler,它完全满足您的需要。现在还没有完成,但是这个psuedo代码可能会让您知道如何完成它
public class ValidationHandler : HttpOperationHandler
{
private readonly HttpOperationDescription _httpOperationDescription;
private readonly Uri _baseAddress;
public ValidationHandler(HttpOperationDescription httpOperationDescription, Uri baseAddress)
{
_httpOperationDescription = httpOperationDescription;
_baseAddress = baseAddress;
}
protected override IEnumerable<HttpParameter> OnGetInputParameters()
{
return new[] { HttpParameter.RequestMessage };
}
protected override IEnumerable<HttpParameter> OnGetOutputParameters()
{
var types = _httpOperationDescription.InputParameters.Select(x => x.ParameterType);
return types.Select(type => new HttpParameter(type.Name, type));
}
protected override object[] OnHandle(object[] input)
{
var request = (HttpRequestMessage)input[0];
var uriTemplate = _httpOperationDescription.GetUriTemplate();
var uriTemplateMatch = uriTemplate.Match(_baseAddress, request.RequestUri);
var validationResults = new List<ValidationResult>();
//Bind the values from uriTemplateMatch.BoundVariables to a model
//Do the validation with Validator.TryValidateObject and add the results to validationResults
//Throw a exception with BadRequest http status code and add the validationResults to the message
//Return an object array with instances of the types returned from the OnGetOutputParmeters with the bounded values
}
}
公共类ValidationHandler:HttpOperationHandler
{
私有只读HttpOperationDescription\u HttpOperationDescription;
专用只读Uri_基地址;
公共验证处理程序(HttpOperationDescription HttpOperationDescription,Uri基地址)
{
_httpOperationDescription=httpOperationDescription;
_基地址=基地址;
}
受保护的重写IEnumerable OnGetInputParameters()
{
返回新的[]{HttpParameter.RequestMessage};
}
受保护的重写IEnumerable OnGetOutputParameters()
{
var types=\u httpOperationDescription.InputParameters.Select(x=>x.ParameterType);
返回类型。选择(type=>newhttpparameter(type.Name,type));
}
受保护的重写对象[]OnHandle(对象[]输入)
{
var请求=(HttpRequestMessage)输入[0];
var uriTemplate=_httpOperationDescription.GetUriTemplate();
var uriTemplateMatch=uriTemplate.Match(_baseAddress,request.RequestUri);
var validationResults=新列表();
//将uriTemplateMatch.BoundVariables中的值绑定到模型
//使用Validator.TryValidateObject进行验证,并将结果添加到validationResults
//抛出一个带有BadRequest http状态代码的异常,并将validationResults添加到消息中
//返回一个对象数组,其中包含从OnGetOutputParmeters返回的具有有界值的类型的实例
}
}
OnGetInputParameters值告诉OnHandle方法的预期输出,OnGetOutputParameters告诉OnHandle方法的预期输出(稍后将注入服务中的方法)
然后,您可以使用HttpConfiguration将处理程序添加到路由中,如下所示:
var httpConfiguration = new HttpConfiguration
{
RequestHandlers = (collection, endpoint, operation) => collection.Add(new ValidationHandler(operation, endpoint.Address.Uri))
};
RouteTable.Routes.MapServiceRoute<MyResource>("MyResource", httpConfiguration);
var-httpConfiguration=新的httpConfiguration
{
RequestHandler=(集合、端点、操作)=>collection.Add(新的ValidationHandler(操作、端点、地址、Uri))
};
RouteTable.Routes.MapServiceRoute(“MyResource”,httpConfiguration);
好的,我终于设法让我的模型工作了。我编写了一个验证处理程序和两个扩展方法。验证处理程序的第一件事:
public class ValidationHandler<T> : HttpOperationHandler
{
private readonly HttpOperationDescription _httpOperationDescription;
public ValidationHandler(HttpOperationDescription httpOperationDescription)
{
_httpOperationDescription = httpOperationDescription;
}
protected override IEnumerable<HttpParameter> OnGetInputParameters()
{
return _httpOperationDescription.InputParameters
.Where(prm => prm.ParameterType == typeof(T));
}
protected override IEnumerable<HttpParameter> OnGetOutputParameters()
{
return _httpOperationDescription.InputParameters
.Where(prm => prm.ParameterType == typeof(T));
}
protected override object[] OnHandle(object[] input)
{
var model = input[0];
var validationResults = new List<ValidationResult>();
var context = new ValidationContext(model, null, null);
Validator.TryValidateObject(model, context, validationResults,true);
if (validationResults.Count == 0)
{
return input;
}
else
{
var response = new HttpResponseMessage()
{
Content = new StringContent("Model Error"),
StatusCode = HttpStatusCode.BadRequest
};
throw new HttpResponseException(response);
}
}
}
公共类ValidationHandler:HttpOperationHandler
{
私有只读HttpOperationDescription\u HttpOperationDescription;
公共验证处理程序(HttpOperationDescription HttpOperationDescription)
{
_httpOperationDescription=httpOperationDescription;
}
受保护的重写IEnumerable OnGetInputParameters()
{
返回\u httpOperationDescription.InputParameters
其中(prm=>prm.ParameterType==typeof(T));
}
受保护的重写IEnumerable OnGetOutputParameters()
{
返回\u httpOperationDescription.InputParameters
其中(prm=>prm.ParameterType==typeof(T));
}
受保护的重写对象[]OnHandle(对象[]输入)
{
var模型=输入[0];
var validationResults=新列表();
var context=新的ValidationContext(model,null,null);
TryValidateObject(模型、上下文、validationResults、true);
if(validationResults.Count==0)
{
返回输入;
}
其他的
{
var response=newhttpresponsemessage()
{
内容=新的StringContent(“模型错误”),
StatusCode=HttpStatusCode.BadRequest
};
抛出新的HttpResponseException(响应);
}
}
}
请注意处理程序如何接收T对象,这主要是因为我想验证API中的所有模型类型。因此,OnGetInputParameters指定处理程序需要接收一个T类型对象,OnGetOutputParameters指定处理程序需要返回一个具有相同T类型的对象,以防满足验证策略(如果不满足),查看on handle方法如何抛出异常,让客户端知道存在验证问题
现在我需要注册处理程序,为此我编写了几个扩展方法,以Pedro Felix的博客为例(这个博客对我帮助很大,对整个处理程序操作有一些很好的解释)。以下是扩展方法:
public static WebApiConfiguration ModelValidationFor<T>(this WebApiConfiguration conf)
{
conf.AddRequestHandlers((coll, ep, desc) =>
{
if (desc.InputParameters.Any(p => p.ParameterType == typeof(T)))
{
coll.Add(new ValidationHandler<T>(desc));
}
});
return conf;
}
publicstaticwebapiconfigurationmodelvalidationfor(此WebApiConfiguration配置)
{
conf.AddRequestHandlers((coll、ep、desc)=>
{
if(desc.InputParameters.Any(p=>p.ParameterType==typeof(T)))
{
coll.Add(新的ValidationHandler(desc));
}
});
返回形态;
}
因此,该方法检查操作中是否存在T类型参数,如果存在,则将处理程序添加到该特定操作中
这个方法调用另一个扩展方法AddRequestHandler,如果存在,则该方法添加新的处理程序而不删除以前注册的处理程序
public static WebApiConfiguration AddRequestHandlers(
this WebApiConfiguration conf,
Action<Collection<HttpOperationHandler>,ServiceEndpoint,HttpOperationDescription> requestHandlerDelegate)
{
var old = conf.RequestHandlers;
conf.RequestHandlers = old == null ? requestHandlerDelegate :
(coll, ep, desc) =>
{
old(coll, ep, desc);
};
return conf;
}
publicstaticwebapiconfigurationaddrequesthandlers(
这是WebApiConf
var config = new WebApiConfiguration();
config.ModelValidationFor<T>(); //Instead of passing a T object pass the object you want to validate
routes.SetDefaultHttpConfiguration(config);
routes.MapServiceRoute<YourResourceObject>("SomeRoute");
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);
}
}