6

情况

我有一个包含三列的表的 LINQ-TO-SQL 模型。通常的ID(身份,自动生成),然后是int类型的 Avarchar(MAX)类型的B。所有列都在数据库中定义为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.Bnull,正如预期的那样
  4. 然后ModelState.IsValid返回true ?!?
  5. 对db.SubmitChanges()的调用失败并出现异常

问题

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

解决方法

我尝试的一件事是通过包含以下代码向数据类添加数据注释。它没有用。

  [MetadataType(typeof(MyTableMetadata))]
  public partial class MyTable
  {
  }

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

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

4

4 回答 4

1

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

于 2012-09-07T09:39:54.850 回答
1

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

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

于 2012-09-11T09:18:29.300 回答
1

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

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

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

于 2012-09-12T18:26:05.113 回答
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());
    }
}
于 2013-09-28T12:08:42.210 回答