none
mvc3 用ModelState.IsValid进行 表单验证问题 RRS feed

  • 问题

  • 本人采用NHibernate 进行MVC3开发练习,有以下两类:
    (大类:FirstAssetsClass,小类:SecondAssetsClass 一个大类可以包含多个小类)

    public  class FirstAssetsClass
        {
            [DisplayName("大类")]
            [Required(ErrorMessage = "请选择一个大类")]
            public virtual Guid FirstAssetsClassID { get; set; }
            [StringLength(50,MinimumLength=1, ErrorMessage = "{0}必须在{2}至{1}个字符之间")]
            [DisplayName("大类名称")]
            [Required]
             public virtual string FirstAssetsClassName{ get; set; }
        }
    public class SecondAssetsClass
        {
            [DisplayName("小类 ")]
            [Required(ErrorMessage="请选择一个小类")]
            public virtual Guid SecondAssetsClassID { get; set; }
            [StringLength(50,MinimumLength =0, ErrorMessage = "{0}必须在{2}至{1}个字符之间")]
            [Required]
            [DisplayName("小类名称")]
            public virtual string SecondAssetsClassName { get; set; }
            //此句用于表示表间的NHibernate多对一关系统映射
            public virtual FirstAssetsClass  FirstAssetsClass { get; set; }
         }

    NHibernate映射文件如下:

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.MvcPowerTeamManage">
      <class name ="NHibernate.MvcPowerTeamManage.Common.Assets.FirstAssetsClass,NHibernate.MvcPowerTeamManage" table ="firstAssetsClass">
        <id name="FirstAssetsClassID" column="firstAssetsClassID" type="System.Guid">
          <generator class="guid.comb"></generator>
        </id>
        <property name="FirstAssetsClassName" column="firstAssetsClassName" type="System.String"></property>
       
      </class>
    </hibernate-mapping>

    <?xml version="1.0" encoding="utf-8" ?>
    <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly ="NHibernate.MvcPowerTeamManage">
      <class name ="NHibernate.MvcPowerTeamManage.Common.Assets.SecondAssetsClass,NHibernate.MvcPowerTeamManage" table ="secondAssetsClass">
        <id name="SecondAssetsClassID" column="secondAssetsClassID" type="System.Guid">
          <generator class="guid.comb"></generator>
        </id>
        <property name="SecondAssetsClassName" column="secondAssetsClassName" type="System.String"></property>
        <many-to-one name="FirstAssetsClass" column="firstAssetsClassID" 
                     class="NHibernate.MvcPowerTeamManage.Common.Assets.FirstAssetsClass" ></many-to-one>
      </class >
    </hibernate-mapping>

    以下为增加小类时的网页文件:

    @model .MvcPowerTeamManage.Common.Assets.SecondAssetsClass
    @{
        ViewBag.Title = "增加小类";
        Layout = "~/Views/Shared/_LayOut_ChildMenu.cshtml";
    }
    <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
    @using (Html.BeginForm())
    {
        @Html.ValidationSummary(true)
        <fieldset>
             <legend>SecondAssetsClass</legend>
                @Html.HiddenFor(m=>m.FirstAssetsClass.FirstAssetsClassID)
            <div class="editor-label">
                @Html.LabelFor(model => model.SecondAssetsClassName)
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => model.SecondAssetsClassName)
                @Html.ValidationMessageFor(model => model.SecondAssetsClassName)
            </div>
            <p>
                <input type="submit" value="Create" />
            </p>
        </fieldset>
    }

    表单提交后的Controler中的代码:

    public ActionResult AddSecondClass(SecondAssetsClass NewSecondAssetsClass)
            //public ActionResult AddSecondClass(string  NewSecondAssetsClass,Guid firstAssetsClassID)
            {
                if (ModelState.IsValid)
                {
                   SecondAssetsClass _SecondAssetsClass=new SecondAssetsClass();
                    _SecondAssetsClass.Add(NewSecondAssetsClass);
                    GetSecondAssetsClasses(NewSecondAssetsClass.FirstAssetsClass.FirstAssetsClassID);//刷新Json数据
                    return RedirectToAction("ClassEdit");
                    
                }
                else
                {
                    return View(NewSecondAssetsClass);
                }
            }

    问题是这样:提交后,ModelState.IsValid总是为“false”,因为ModelState中包含有对NewSecondAssetsClass.FirstAssetsClass.FirstAssetsClassName的验证,因为表单中没有提交此值。所以总是为“假”。当然SecondAssetsClass类可以改成如下:

    public class SecondAssetsClass { [DisplayName("小类 ")] [Required(ErrorMessage="请选择一个小类")] public virtual Guid SecondAssetsClassID { get; set; } [StringLength(50,MinimumLength =0, ErrorMessage = "{0}必须在{2}至{1}个字符之间")] [Required] [DisplayName("小类名称")] public virtual string SecondAssetsClassName { get; set; }

    public virtual Guid FirstAssetsClassID { get; set; } }

    但这样似乎又失去使用NHibernat的便捷性,每次都要通过FirstAssetsClassID查询一次FirstAssetsClassName,请问有没有方法在不改变当前数据结构的情况下,只对ModelState.IsValid中的各值进行处理来实现。

    当然可在Controler中,对 if (ModelState.IsValid)这句进行更改,采用逐项判断ModelState需要判断的内容,可以实现。但如表单内容项较多时较麻烦。
    不知有无更好的解决?谢谢!

    2012年8月8日 14:27

答案

  • 其实mvc 可以去除不必要的验证字段的

    可以  [Bind(Include="name")] 就包括一个字段 或者[Bind(Exclude="name")] 排除一个字段

    当然也可以直接移除          ModelState.Remove("name"),具体代码如下

         [HttpPost]
            [Bind(Include = "name")]
            public JsonResult FileUpload(string id)
            {
                ModelState.Remove("name");
                UploadContext upload = UploadContextFactory.GetUploadContext(id);
                if ((upload != null) && (upload.Status == UploadStatus.Complete))
                {
                    upload.SaveFile("filepath", Request.MapPath("~/uploadfiles/"));
                }
                return Json(new { result = Convert.ToInt16(100) });
            }


    认真的活,认真的爱!

    2012年8月12日 10:42
    版主
  • 因为我用NHibernate作为数据据映射,所以在类中存在以下表示关系的字段(类型为类)

     //此句用于表示表间的NHibernate多对一关系统映射
           
    public virtual FirstAssetsClass  FirstAssetsClass { get; set; }
    FirstAssetsClass类中存的FirstAssetsClassID字段需要进行验证。如采用[Bind(Exclude="XXX")] 排除一个字段,则只能排除小类中的FirstAssetsClass 字段,而不能排除FirstAssetsClassName字段。

    当然你的方法在一般情况下可用,谢谢指导!

    • 已标记为答案 夏冰松 2012年8月18日 14:02
    2012年8月18日 14:01

全部回复

  • 已解决:用以下两种方法都可加以解决

    方法一:在新建时把原Action

            public ActionResult AddSecondClass(Guid id)
            {
                Guid firstAssetsClassID = id;
                SecondAssetsClass NewSecondAssetsClass = new SecondAssetsClass();
                NewSecondAssetsClass.FirstAssetsClass = new FirstAssetsClass();
                NewSecondAssetsClass.FirstAssetsClass.FirstAssetsClassID = firstAssetsClassID;
                return View(NewSecondAssetsClass);
            }

    更改为以下:

           public ActionResult AddSecondClass(Guid id)
            {
                Guid firstAssetsClassID = id;
                SecondAssetsClass NewSecondAssetsClass = new SecondAssetsClass();
                NewSecondAssetsClass.FirstAssetsClass = new FirstAssetsClass();
                NewSecondAssetsClass.FirstAssetsClass.FirstAssetsClassID = firstAssetsClassID;
                //新增以下初始设置,值可任意设置,因它是不会加入数据库中的,只要满足类中的对应字段要求即可
                NewSecondAssetsClass.FirstAssetsClass.FirstAssetsClassName = "newFirstClassName";
                return View(NewSecondAssetsClass);
            }

    再在表单中新加对应的隐藏域:

    @model NHibernate.MvcPowerTeamManage.Common.Assets.SecondAssetsClass
    @{
        ViewBag.Title = "增加小类";
        Layout = "~/Views/Shared/_LayOut_ChildMenu.cshtml";
    }
    <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
    @using (Html.BeginForm())
    {
        @Html.ValidationSummary(true)
        
        <fieldset>
             <legend>SecondAssetsClass</legend>
        @Html.HiddenFor(m=>m.FirstAssetsClass.FirstAssetsClassID) 
        @---*新增的隐藏域---*@
        @Html.HiddenFor(m=>m.FirstAssetsClass.FirstAssetsClassName)      
        @*--------------*@
            <div class="editor-label">
                @Html.LabelFor(model => model.SecondAssetsClassName)
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => model.SecondAssetsClassName)
                @Html.ValidationMessageFor(model => model.SecondAssetsClassName)
            </div>
            <p>
                <input type="submit" value="Create" />
            </p>
        </fieldset>
    }
    <div>
        @Html.ActionLink("Back to List", "Index")
    </div>

    那么就能在Action 直接使用ModelState.IsValid进行验证;

    方法二:

            public ActionResult AddSecondClass(Guid id)
            {
                Guid firstAssetsClassID = id;
                SecondAssetsClass NewSecondAssetsClass = new SecondAssetsClass();
                NewSecondAssetsClass.FirstAssetsClass = new FirstAssetsClass();
                NewSecondAssetsClass.FirstAssetsClass.FirstAssetsClassID = firstAssetsClassID;
               //不增加以下句--------
    //NewSecondAssetsClass.FirstAssetsClass.FirstAssetsClassName = "newFirstAssetsClassName";
    //--------------------------------------
                return View(NewSecondAssetsClass);
            }

    提交页面如下:

    @model NHibernate.MvcPowerTeamManage.Common.Assets.SecondAssetsClass
    @{
        ViewBag.Title = "增加小类";
        Layout = "~/Views/Shared/_LayOut_ChildMenu.cshtml";
    }
    <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
    @using (Html.BeginForm())
    {
        @Html.ValidationSummary(true)
        
        <fieldset>
             <legend>SecondAssetsClass</legend>
        @Html.HiddenFor(m=>m.FirstAssetsClass.FirstAssetsClassID) 
        @*---不增以下隐藏域---*@
        @*@Html.HiddenFor(m=>m.FirstAssetsClass.FirstAssetsClassName)*@      
        @*--------------*@
            <div class="editor-label">
                @Html.LabelFor(model => model.SecondAssetsClassName)
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => model.SecondAssetsClassName)
                @Html.ValidationMessageFor(model => model.SecondAssetsClassName)
            </div>
            <p>
                <input type="submit" value="Create" />
            </p>
        </fieldset>
    }
    <div>
        @Html.ActionLink("Back to List", "Index")
    </div>

    更改提交后的验证,去除不必要的字段

            [HttpPost]
            public ActionResult AddSecondClass(SecondAssetsClass NewSecondAssetsClass)
            {
                if (ModelState["FirstAssetsClass.FirstAssetsClassID"].Errors.Count == 0
                    & ModelState["SecondAssetsClassName"].Errors.Count == 0)
                //if(ModelState.IsValid)
                {
                    SecondAssetsClass _SecondAssetsClass = new SecondAssetsClass();
                    _SecondAssetsClass.Add(NewSecondAssetsClass);
                    GetSecondAssetsClasses(NewSecondAssetsClass.FirstAssetsClass.FirstAssetsClassID);//刷新Json数据
                    return RedirectToAction("ClassEdit");
                    
                }
                else
                {
                    return View(NewSecondAssetsClass);
                }
            }
    即可完成数据的验证。

    2012年8月9日 17:47
  • 其实mvc 可以去除不必要的验证字段的

    可以  [Bind(Include="name")] 就包括一个字段 或者[Bind(Exclude="name")] 排除一个字段

    当然也可以直接移除          ModelState.Remove("name"),具体代码如下

         [HttpPost]
            [Bind(Include = "name")]
            public JsonResult FileUpload(string id)
            {
                ModelState.Remove("name");
                UploadContext upload = UploadContextFactory.GetUploadContext(id);
                if ((upload != null) && (upload.Status == UploadStatus.Complete))
                {
                    upload.SaveFile("filepath", Request.MapPath("~/uploadfiles/"));
                }
                return Json(new { result = Convert.ToInt16(100) });
            }


    认真的活,认真的爱!

    2012年8月12日 10:42
    版主
  • 因为我用NHibernate作为数据据映射,所以在类中存在以下表示关系的字段(类型为类)

     //此句用于表示表间的NHibernate多对一关系统映射
           
    public virtual FirstAssetsClass  FirstAssetsClass { get; set; }
    FirstAssetsClass类中存的FirstAssetsClassID字段需要进行验证。如采用[Bind(Exclude="XXX")] 排除一个字段,则只能排除小类中的FirstAssetsClass 字段,而不能排除FirstAssetsClassName字段。

    当然你的方法在一般情况下可用,谢谢指导!

    • 已标记为答案 夏冰松 2012年8月18日 14:02
    2012年8月18日 14:01