Asp.net mvc 3 受保护的内部集属性的模型绑定

Asp.net mvc 3 受保护的内部集属性的模型绑定,asp.net-mvc-3,c#-4.0,properties,model-binding,Asp.net Mvc 3,C# 4.0,Properties,Model Binding,在我的模型类中,我有多个属性是“受保护的内部集”。一旦创建了这些属性,就不能对其进行修改。说到这里,我很难创建一个模型绑定器,它允许在创建时设置这些属性。为了只设置一次这些属性,最好的方法是什么 不幸的是,这不是你可以自动完成的。您必须为每种类型创建一个唯一的模型绑定器,然后使用构造函数参数创建对象。只有在尚未设置私有字段的情况下,才能设置保护的set方法设置私有字段吗 public string PropertyName { get { return this.private

在我的模型类中,我有多个属性是“受保护的内部集”。一旦创建了这些属性,就不能对其进行修改。说到这里,我很难创建一个模型绑定器,它允许在创建时设置这些属性。为了只设置一次这些属性,最好的方法是什么

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

只有在尚未设置私有字段的情况下,才能设置保护的set方法设置私有字段吗

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

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

  }
}

private string privateField;

我是用一个定制的模型活页夹做的。我不仅有私有setter,而且MVC操作的参数是一个接口,我没有无参数构造函数(trifecta!);所有这些都不适用于默认的模型绑定器

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

// 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)。在我的例子中,我不想为每个可以实现接口的类编写一个模型绑定器,所以我使用了更多的反射来匹配类,找到一个构造函数,将默认值传递给它,然后循环遍历类上的每个属性,并从请求值设置它。我有一个单独的方法,在运行基于消息的操作之前验证消息。

为什么不使用视图模型?我会使用视图模型,但这会导致太多重复代码,而且编辑和创建共享同一视图。我只需要绑定数据,如果它是create@mmekaiel-听起来你让事情变得比你必须做的要困难得多。只要咬紧牙关,创建特定的视图模型,或者忘记使用受保护的属性。但是,我该如何在创建这些属性后不允许更改它们呢?@mmekaiel-你不能阻止它,但你为什么要更改它们呢?我同意,把它做得“正确”是很好的,但是当这样做的努力是如此巨大的时候,它就不值得了。为这些特殊属性(主要是字符串)创建独特的模型绑定器,是我遇到麻烦的部分。我所做的一切似乎都无法正确绑定数据。我会使用视图模型,但这将是太多的重复代码,而且编辑和创建共享相同的视图。我只需要绑定数据,如果它是create@mmekaiel-据我所知,您不能将模型绑定器仅限于特定类型的请求,它要么是全部,要么是全部(如果这是错误的,Darin可能会纠正我)。所以要么你做所有的工作,要么什么都不做(意味着你不使用受保护的属性)。如果我为所有字符串创建一个模型绑定器,那么无论属性是定期设置的还是受保护的内部设置的,它的工作都会不一样吗?@mmekaiel-我不知道你在问什么。@mmekaiel-还有,别自欺欺人。您必须为所有类型的请求建立模型绑定,因为当验证失败时,您需要绑定输入的值,这意味着为您的案例使用特殊的模型绑定器。