受保护的内部集属性的模型绑定

时间:2012-05-29 15:21:48

标签: asp.net-mvc-3 c#-4.0 properties model-binding

在我的模型类中,我有多个属性是“受保护的内部集”。创建这些属性后,它们将无法修改。话虽如此,我很难创建一个模型绑定器,允许在创建时设置这些属性。为了能够只设置一次这些属性,最好的方法是什么?

3 个答案:

答案 0 :(得分:1)

不幸的是,这不是你可以自动完成的事情。您必须为每种类型创建一个唯一的模型绑定器,然后使用构造函数参数创建对象。

答案 1 :(得分:1)

我是使用自定义模型绑定器完成的。我不仅拥有私有的setter,而且我的MVC操作的参数是一个接口,而且我没有无参数的构造函数(三元组!);这些都不适用于默认的模型绑定器。

在您的情况下,您只需为您的类型制作自定义模型活页夹。使用默认值创建类的新实例。然后只需使用Reflection在类上设置属性。反射方法不关心属性的可访问性。像这样:

// assuming your class looks like this
public class MyClass
{
    public int MyInt { get; private set; }
    public string MyString { get; private set; }

    public MyClass(int myInt, string myString)
    {
        MyInt = myInt;
        MyString = myString;
    }
}

// model binder is like this
public class MyModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext,
        ModelBindingContext bindingContext,
        Type modelType)
    {
        // initialize with default values, they will be overwritten
        MyClass myClass = new MyClass(default(int), default(string));
        // get the reflection info on the int property
        PropertyInfo intProperty = typeof(MyClass).GetProperty("MyInt");
        // get the int value from the request
        int myIntValue = int.Parse(bindingContext.ValueProvider
            .GetValue(intProperty.Name).AttemptedValue);
            // btw, attempted value is a string
        // set the property value, SetValue ignores accessibility modifiers
        intProperty.SetValue(myClass, myIntValue, null);
        // do the same stuff for MyString property
        PropertyInfo stringProperty = typeof(MyClass).GetProperty("MyString");
        string myStringValue = bindingContext.ValueProvider
            .GetValue(stringProperty.Name).AttemptedValue;
        stringProperty.SetValue(myClass, myStringValue, null);
        return myClass;
    }
}

// Your controller action is like this
public ActionResult MyAction([ModelBinder(typeof(MyModelBinder))]
                             MyClass myClass)
{
    ...
}

我想你可以将正确的值传递给构造函数而不使用反射来设置它们:

        ...
        int myIntValue = int.Parse(bindingContext.ValueProvider
            .GetValue(intProperty.Name).AttemptedValue);
        string myStringValue = bindingContext.ValueProvider
            .GetValue(stringProperty.Name).AttemptedValue;
        MyClass myClass = new MyClass(myIntValue, myStringValue);
        ...

但是如果您需要做更多,反射可以让您绕过访问修饰符限制(当然有效的基础结构原因!:D)。在我的例子中,我不想为每个可以实现接口的类编写模型绑定器,所以我使用了更多的反射来匹配类,找到一个构造函数,将默认值传递给它,然后循环遍历每个属性该类并从请求值中设置它。我有一个单独的方法,可以在基于它运行操作之前验证消息。

答案 2 :(得分:0)

只有在尚未设置私有字段的情况下,您是否可以设置受保护的设置方法?

public string PropertyName
{
  get
  {
     return this.privateField;
  }

  protected set
  {
     if (this.privateField == null)
     {
       this.privateField = value;
     }

  }
}

private string privateField;