ModelState.IsValid返回true,即使必需的字符串为null

时间:2012-09-05 01:49:56

标签: asp.net linq-to-sql webforms model-binding

情况

我有一个LINQ-TO-SQL模型,其中包含一个包含三列的表。通常的 ID (标识,自动生成),然后 int A varchar类型的 B (MAX)。所有列都在数据库中定义为 NOT NULL

WebForms 页面上,我声明了一个与项目绑定的DetailsView:

<asp:ValidationSummary runat="server" ShowModelStateErrors="true" />
<asp:DetailsView DataKeyNames="Id" runat="server" ItemType="test.MyTable"
    SelectMethod="..." UpdateMethod="...">
      <Fields>
        <asp:DynamicField DataField="A" />
        <asp:TemplateField>
            <EditItemTemplate>
                <asp:TextBox ID="B" runat="server" TextMode="MultiLine" Columns="80" Rows="8" Text="<%# BindItem.B %>" />
            </EditItemTemplate>
            <ItemTemplate>
                <pre><asp:Label runat="server" Text="<%# Item.B %>"  /></pre>
            </ItemTemplate>
        </asp:TemplateField>
      </Fields>
</asp:DetailsView>

所有这些代码都在ASP.NET 4.5上的Visual Studio 2012中运行。

会发生什么

到目前为止一切顺利。更新和查看作品。当我输入无效值时,问题就开始了。使用“”作为字段 A 会在页面顶部显示一条漂亮的错误消息。好极了!但是,当我使用“”作为字段 B 的值时,会发生这种情况:

    public void DetailsView_UpdateItem(int id)
    {
      var item = db.MyTable.Where(row => row.Id==id).Single();
      TryUpdateModel(item);
      if (ModelState.IsValid)
        db.SubmitChanges();
    }
  1. 调用UpdateItem方法
  2. TryUpdateModel可以将表单值填充到 item 中。
  3. 调试时我可以看到 item.B null ,正如预期的那样
  4. 然后 ModelState.IsValid 返回 true ?!
  5. db.SubmitChanges()的调用因异常而失败
  6. 问题

    我不明白为什么 ModelState.IsValid 会在数据模型指定 B 不能 null 时返回 true EM>。有人可以解释一下吗?我做错了什么?

    的变通方法

    我尝试过的一件事是通过包含以下代码将Data Annotations添加到数据类中。它不起作用。

      [MetadataType(typeof(MyTableMetadata))]
      public partial class MyTable
      {
      }
    
      public class MyTableMetadata
      {
        [Required]
        [StringLength(255,MinimumLength=1)]
        public string B { get; set; }
      }
    

    很明显,我可以在 UpdateItem 方法中手动检查 null ,或者我可以添加一个RequiredFieldValidator - 但我不想这样做。

4 个答案:

答案 0 :(得分:1)

只是一些随意的建议: 确保您正在引用System.ComponentModel.DataAnnotations 3.5。 (不是3.6)或其他一些正确的命名空间(据我所知,只有一些用于WCF RIA服务)。 尝试不同的设置 [DisplayFormat(ConvertEmptyStringToNull = ...)] 确保您正在执行POST请求=)

答案 1 :(得分:1)

为什么你认为你得到一个空值?空字符串不等于null。您可以通过手动检查null来确认这一点,就像您建议的那样。

除了非空约束之外,您还可以添加StringLengthAttribute来强制执行非空约束。

答案 2 :(得分:1)

TryUpdateModel()方法本质上(简化了很多)使用模型类中的字段/属性的名称来查找帖子的表单集合中的已发布值。如果是asp.net网格,并且您为文本框指定了ID = B,则控件的名称将变为类似于ctl00 $ B.模型绑定器无法连接点并从表单集合中获取值,即使它存在于帖子中。

我觉得在您的可编辑字段中使用“asp:BoundField”可能会解决您的问题。您也可以考虑编写自定义模型绑定器或自己分配值。更改模型中属性的名称以匹配生成的控件的名称是另一种解决问题的方法(请不要选择此选项。)

当TryUpdateModel()在帖子中找到值但是无法将值转换为模型中的类型时,它将返回false。否则返回true。

答案 3 :(得分:0)

公共类SecurityLayer     {         StringBuilder SB = new StringBuilder();

    public string SecurityValidate(object OBJ)
    {
        SB.Clear();
        var context = new ValidationContext(OBJ, serviceProvider: null, items: null);
        var results = new List<ValidationResult>();

        var isValid = Validator.TryValidateObject(OBJ, context, results);

        if (!isValid)
        {
            foreach (var validationResult in results)
            {
                //    Console.WriteLine(validationResult.ErrorMessage);
                SB.AppendLine(validationResult.ErrorMessage);
            }
        }

        return (SB.Length == 0 ? "SUCCESS" : SB.ToString());
    }
}