C# 验证模型属性WCF Web APi

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.

我有一组使用WCF Web Api托管的服务,我需要做的是验证应用程序模型中的属性

例如,在MVC 3中,我在模型中装饰属性,如下所示:

    [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);
    }
}