我该如何验证MVC3页面的不同部分

时间:2012-04-01 14:22:03

标签: c# asp.net-mvc-3 validation

我试图理解我应该如何独立验证我的MVC3页面的客户端部分,并提出了我想要实现的简化版本。

如果我使用一种形式:
优点:当我提交回“PostData”控制器方法时,我会收到表单中包含的所有数据。在这种情况下,值“name”和“description”,这意味着我可以实例化“PersonH​​obbyModel”并分配我收到的数据。我可以存储在数据库中,也可以返回相同的视图。

缺点:我无法独立验证。因此,如果“名称”没有完成,我完成“描述”,我仍然可以提交页面。 (这是我想要做的简单版本,我会有更多的字段而不仅仅是“名称”和“描述”)

有两种形式: 优点:我可以独立验证。

缺点:控制器方法只接收子表单数据,在这种情况下,“人名”或“爱好描述”,这意味着我无法重新创建“PersonH​​obbyModel”的完整实例。

这是模型:

 public class Person {

    [Display(Name = "Person name:")]
    [Required(ErrorMessage = "Person name required.")]
    public string Name { get; set; }
}

public class Hobby {

    [Display(Name = "Hobby  description:")]
    [Required(ErrorMessage = "Hobby description required.")]
    public string Description { get; set; }
}

public class PersonHobbyModel {

    public PersonHobbyModel() {
        this.Person = new Person();
        this.Hobby = new Hobby();
    }

    public Person Person { get; set; }
    public Hobby Hobby { get; set; }
}

这是控制器:

 public class PersonHobbyController : Controller
{
    //
    // GET: /PersonHobby/

    public ActionResult Index()
    {
        var model = new PersonHobbyModel();
        return View(model);
    }


    public ActionResult PostData(FormCollection data) {
        var model = new PersonHobbyModel();

        TryUpdateModel(model.Person, "Person");
        TryUpdateModel(model.Hobby,"Hobby");

        return View("Index", model);
    }

}  

这是观点:

@model MultipleFORMStest.PersonHobbyModel
@{
    ViewBag.Title = "Index";
}
<h2>
    Index</h2>
@using (Html.BeginForm("PostData", "PersonHobby")) {
    <div>
        @Html.LabelFor(model => model.Person.Name)
        @Html.TextBoxFor(model => model.Person.Name)
        @Html.ValidationMessageFor(model => model.Person.Name)
        <input type="submit" value="Submit person" />
    </div>
}
@using (Html.BeginForm("PostData", "PersonHobby")) {
    <div>
        @Html.LabelFor(model => model.Hobby.Description)
        @Html.TextBoxFor(model => model.Hobby.Description)
        @Html.ValidationMessageFor(model => model.Hobby.Description)
        <input type="submit" value="Submit hobby" />
    </div>
    }

更新1
我没有提及,因为我想让问题尽可能简单,但对于其中一个部分我正在使用“jquery ui对话框”。我最初使用DIV来定义对话框,我在主窗体中有这个对话框。这会导致一个问题,因为我无法在客户端验证“JQuery对话框表单”独立于表单的其余部分。

说这个jquery确实从主窗体中删除了“div jquery ui dialog”,这使得我以自己的形式包含了对话框。出于这个原因,我最终得到了两种形式。优点是我现在可以独立验证“jquery对话框ui表单”。

但我很困惑,我应该如何处理从客户端上的各种表单提交的服务器数据,因为用户可能已禁用JS。如果我从一个表单提交,我无法以其他形式访问数据。

更新2
谢谢你的回复。我相信我确实需要两个表单和两个实体,因为我想在客户端上独立地验证它们(除了被“Jquery UI Dialog”强制使用之外)。例如,如果我有,而不是一个爱好,我有一个爱好列表,我可以在同一视图中的网格中显示。所以我无法填写人名,但继续向网格添加爱好,如果我没有完成业余爱好描述我会得到验证错误。 (对不起,我应该在最初的问题中包括我的两个更新,但为了清楚起见,我希望保持它像posible一样简单)

2 个答案:

答案 0 :(得分:4)

从我的角度来看,您有一个与两个实体模型相对应的视图模型。在您的位置,我将使用单个表单并验证视图模型,而不是真正将其视为两个(依赖)实体。在操作中接收视图模型,而不是通用表单集合,并通过数据注释属性使用基于模型的验证。获得有效的已发布模型后,您可以将其转换为适当的实体并将其保存到数据库中。

模型

public class PersonHobbyViewModel {

    [Display(Name = "Person name:")]
    [Required(ErrorMessage = "Person name required.")]
    public string Name { get; set; }

    [Display(Name = "Hobby  description:")]
    [Required(ErrorMessage = "Hobby description required.")]
    public string Description { get; set; }
}

控制器

public class PersonHobbyController : Controller
{
    //
    // GET: /PersonHobby/
    [HttpGet] // mark as accepting only GET
    public ActionResult Create() // Index should probably provide some summary of people and hobbies
    {
        var model = new PersonHobbyViewModel();
        return View(model);
    }

    [HttpPost] // mark as accepting only POST
    public ActionResult Create(PersonHobbyViewModel model) {

        if (ModelState.IsValid) {
           var person = new Person { Name = model.Name };
           var hobby = new Hobby { Description = model.Description };
           person.Hobbies = new List<Hobby> { hobby };

           db.Persons.Add( person );
           db.SaveChanges();
        }

        return RedirectToAction( "details", new { id = person.Id } ); // view the newly created entity
    }
}

查看

@model MultipleFORMStest.PersonHobbyViewModel
@{
    ViewBag.Title = "Create";
}
<h2>
    Create</h2>
@using (Html.BeginForm("Create", "PersonHobby")) {
    <div>
        @Html.LabelFor(model => model.Person.Name)
        @Html.TextBoxFor(model => model.Person.Name)
        @Html.ValidationMessageFor(model => model.Person.Name)
        <input type="submit" value="Submit person" />
    </div>

    <div>
        @Html.LabelFor(model => model.Hobby.Description)
        @Html.TextBoxFor(model => model.Hobby.Description)
        @Html.ValidationMessageFor(model => model.Hobby.Description)
        <input type="submit" value="Submit hobby" />
    </div>
}

答案 1 :(得分:1)

我认为您的ViewModel应该只针对您所代表的视图。在这种情况下,我会使用像这样的ViewModel

public class AddPersonHobbyViewModel
{
  [Required]
  [Display (Name="Person Name")]
  public string PersonName { set;get;}

  [Required]
  [Display (Name="Hobby Description")]
  public string HobbyDescription { set;get;}

}

在我的PostData ActionMethod中,我将检查模型验证

[HttpPost]
public ActionResult PostData(AddPersonHobbyViewModel objVM)
{
  if(ModelState.IsValid)
  {
    // Everything is fine. Lets save and redirect to another get View( for PRG pattern)
  }
  return View(objVm);
}

您只能在视图中使用一个强类型为AddPersonHobbyViewModel

的表单
@model AddPersonHobbyViewModel

@using (Html.BeginForm("PostData","Person"))
{
 @Html.TextBoxFor(m=>m.PersonName)
 @Html.ValidationMessageFor(m => m.PersonName)
 @Html.TextBoxFor(m=>m.HobbyDescription )
 @Html.ValidationMessageFor(m => m.HobbyDescription )
 <input type="submit" value="Save" />
}