ASP.NET MVC - [Bind(Exclude = "Id")]的替代方案

21

有没有[Bind(Exclude="Id")]的替代方案(相关问题)?

我能写一个模型绑定器吗?

5个回答

36

是的,有一种方法:它被称为视图模型。视图模型是专门针对给定视图的特定需求而设计的类。

因此,不再需要:

public ActionResult Index([Bind(Exclude = "Id")] SomeDomainModel model)

使用:

public ActionResult Index(SomeViewModel viewModel)

视图模型(View Model)只包含需要绑定的属性。然后您可以在视图模型和模型之间进行映射。使用AutoMapper可以简化此映射。

作为最佳实践,我建议您始终使用视图模型来处理视图的数据传输。


2
+1 这是我见过的关于 ViewModel vs Business model 最好的描述。我从来没有从安全角度考虑过它。但这是使用视图模型的原因,至少对于 http 来说。 - jgauffin
9
@Darin:当您有一个包含许多属性(以及关系、验证规则等)的大型复杂域对象图需要在表单上呈现时,您是否重新定义视图模型中所有相关属性,并手动复制它们之间的所有属性等?这似乎会导致很多重复、硬依赖和冗余代码,因此我一直像避开瘟疫一样避免这种情况。即使这似乎是“正确”的方法,在实践中,我也看不出怎样才能避免所有尴尬的重复和重复代码...?? - mindplay.dk
1
@mindplay.dk,我把所有需要的东西都放在视图模型里了。如果我的初始领域模型有一些复杂的属性图,我可能会将它展平。但再次强调,我仅包含需要在视图中显示/编辑的内容。如果只是为了将一些数据保存到隐藏字段中(类似于ViewState),那么我就不会在视图模型中包含这些属性。我只包含ID,以允许我从任何存储位置检索此信息。至于手动复制,不,我不会手动操作,我使用AutoMapper来帮我完成这项工作。 - Darin Dimitrov
2
@Darin:但是您是否复制了在视图中所需的领域模型中的所有属性?验证注释呢?您是否复制了所有这些内容,还是只在视图模型上有验证注释?(感谢分享!) - mindplay.dk
2
@mindplay.dk,我只在视图上复制我需要的内容。就验证而言,我会在视图模型上执行验证。我使用FluentValidation.NET进行此操作。不要使用DataAnnotations。 - Darin Dimitrov
显示剩余4条评论

22

您可以使用属性直接排除属性,方法如下:

[BindNever]

15

我想出了一个非常简单的解决方案。

public ActionResult Edit(Person person)
{
    ModelState.Remove("Id"); // This will remove the key 

    if (ModelState.IsValid)
       {
           //Save Changes;
       }
    }
}

10

除了现有答案之外,C# 6使得以更安全的方式排除属性成为可能:

public ActionResult Edit(Person person)
{
    ModelState.Remove(nameof(Person.Id));

    if (ModelState.IsValid)
       {
           //Save Changes;
       }
    }
}
或者
public ActionResult Index([Bind(Exclude = nameof(SomeDomainModel.Id))] SomeDomainModel model)

我喜欢这个答案,但我仍然认为在设计模式和关注点分离方面应该使用ViewModelsPOCO's - Chef_Code
如果您想要排除其中两个,您会如何处理? - John Lord

3

正如Desmond所说,我发现remove非常易于使用,而且我开发了一个简单的扩展程序,可以方便地忽略多个属性...

    /// <summary>
    /// Excludes the list of model properties from model validation.
    /// </summary>
    /// <param name="ModelState">The model state dictionary which holds the state of model data being interpreted.</param>
    /// <param name="modelProperties">A string array of delimited string property names of the model to be excluded from the model state validation.</param>
    public static void Remove(this ModelStateDictionary ModelState, params string[] modelProperties)
    {
        foreach (var prop in modelProperties)
            ModelState.Remove(prop);
    }

您可以在您的动作方法中像这样使用它:
    ModelState.Remove(nameof(obj.ID), nameof(obj.Prop2), nameof(obj.Prop3), nameof(obj.Etc));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接