ModelBinder验证使用反射在getter上中断

时间:2012-07-31 10:50:01

标签: c# reflection asp.net-mvc-4 asp.net-web-api model-binding

我遇到了一个似乎与反射和模型绑定器验证有关的问题,特别是FormatterParameterBinding.ExecuteBindingAsync(..),虽然我可以使用一个方法来做我想做的事情但如果可以的话我会更喜欢它使用财产。

在这里,我正在寻找对模型绑定器验证过程的一些见解,为什么我无法做我想做的事情以及如何解决问题,或者解决它。

设置

public class ModelBindingValidationBreaker
{
    public ModelBindingValidationBreaker()
    {
        Properties = new List<string>();
    }

    public int A { get; set; }
    public int B { get; set; }
    public IList<string> Properties { get; set; }

    /*// Uncomment to break the model binder validation!
    public IList<PropertyInfo> PropertyInfos
    {
        get
        {
            return GetType()
                .GetProperties()
                .Where(pi => Properties.Contains(pi.Name))
                .ToList();
        }
    }//*/

    public IList<PropertyInfo> GetPropertyInfos()
    {
        return GetType()
            .GetProperties()
            .Where(pi => Properties.Contains(pi.Name))
            .ToList();
    }

    public IList<int> LetterCounts
    {
        get
        {
            return Properties.Select(p => p.Length).ToList();
        }
    }
}

一个控制器,其后置动作定义如下

public void Post(ModelBindingValidationBreaker breaker){...}

用这种json调用它:

{
    "Properties": [
        "A"
    ],
    "A": 1,
    "B": 2
}

如果您单步执行操作,可以看到断路器已正确实例化,您可以毫无问题地致电GetPropertyInfos()

如何破解

但是,如果取消注释PropertyInfos属性,则模型绑定器验证会中断。我添加了一个简单的跟踪器来解决这个问题。它显示了以下相关输出:

System.Web.Http.Action: ApiControllerActionSelector;SelectAction;Selected action 'Post(ModelBindingValidationBreaker breaker)'
System.Web.Http.ModelBinding: HttpActionBinding;ExecuteBindingAsync;
System.Web.Http.ModelBinding: FormatterParameterBinding;ExecuteBindingAsync;Binding parameter 'breaker'
System.Net.Http.Formatting: JsonMediaTypeFormatter;ReadFromStreamAsync;Type='ModelBindingValidationBreaker', content-type='application/json'
System.Net.Http.Formatting: JsonMediaTypeFormatter;ReadFromStreamAsync;Value read='OverPostCount.Models.ModelBindingValidationBreaker'
System.Web.Http.ModelBinding: FormatterParameterBinding;ExecuteBindingAsync;
System.Web.Http.ModelBinding: HttpActionBinding;ExecuteBindingAsync;
System.Web.Http.Controllers: CustomController;ExecuteAsync;
System.Net.Http.Formatting: DefaultContentNegotiator;Negotiate;Type='HttpError', formatters=[JsonMediaTypeFormatterTracer, FormUrlEncodedMediaTypeFormatterTracer, FormUrlEncodedMediaTypeFormatterTracer]

当您排除违规的get_PropertyInfos:

时,其中包含此行
System.Web.Http.ModelBinding: FormatterParameterBinding;ExecuteBindingAsync;Parameter 'breaker' bound to the value 'OverPostCount.Models.ModelBindingValidationBreaker'

在“属性”上添加DataContract和相关属性(如[IgnoreDataMember])无法解决问题。来自mvc名称空间的[Bind(Exclude="Properties")]也不是。 Linq似乎不是问题,因为LetterCount不会破坏模型绑定器验证。

我的问题

  1. 为什么PropertyInfos getter会破坏模型绑定器验证器?
  2. 这是Asp.NET web-api中的错误吗?
  3. 有没有办法通过属性,自定义模型绑定器验证器,服务或类似方法来防止这种破坏?
  4. 基本上我不想为整个类或控制器关闭模型绑定验证,但如果我可以为Properties属性关闭它,那就太棒了!

1 个答案:

答案 0 :(得分:4)

作为一般规则,你应该避免使用像PropertyInfos那样具有其他复杂类型属性的复杂类......在用于模型绑定的类中,但是你应该只使用包含模型绑定所需的JUST THE PROPERTIES的简单类进程,而且整个对象图应该不包含循环。模型绑定过程分析不同目的的属性类型(验证属性等),我可以重新分析eac属性类型中包含的子属性...所以复杂的.net类包含循环和很多其他.net类型可能会破坏它。 尝试将属性PropertyInfos设置为内部或将其转换为方法,以便任何模型绑定器组件都不会对其进行处理。