在MVC4中创建和编辑的视图相同

mms*_*ann 31 asp.net-mvc-4

我们可以为创建和编辑操作创建一个剃刀视图吗?

如果是的话,我们如何实现这一目标?

Bar*_*xto 47

我不推荐它.

这应该是一个相当长的答案,因为在正常的MVC GET/POST工作流程的过程,请求和工作流程中涉及很多事情.我将尝试用所需的最少信息回答您的问题,以及为什么我不建议使用相同的视图.

首先,为什么?

  1. 您无法控制可能过度发布的视图;
  2. 没有灵活性;
  3. 不可重复使用的视图或部分;
  4. 难以维护视图(必须在两个操作上测试视图中的一个更改).

我建议的方法是使用不同的操作/视图,但共享公共代码:

正常创建两个视图.

您将拥有重复的代码,但并非所有代码都相同,例如,您可能不希望在创建操作上发送ID,这与您的问题没有直接关系,但使用相同的视图意味着您也发送了相同的数据,不建议这样做,特别是对于过度发布或批量分配.关于质量分配更多信息这里(一种架构方法是我在这里使用了什么).

那么让我们从您将在控制器中收到的内容开始.在这种情况下,我使用了继承,但它不是唯一的策略.

绑定模型

public class UpdateBindingModel : CreateBindingModel {
    // since we are not using the same binding model, 
    // we can have a "real" validation rules on our update binding and view.
    [Required]
    public int? Id {get;set;}
}

public class CreateBindingModel {
    // no id here prevent overposting.
    [Required]
    public string Name {get;set;}
    [Required]
    public int? CountryId {get;set;}
}
Run Code Online (Sandbox Code Playgroud)

这将确保您发送到"创建"和"编辑"的数据是最不需要的,而不是其他任何内容.

然后让我们看看将发送到View的View Models,对于这个例子,我将包含一个List,用于选择一些值,但不应该发布(列表)到控制器,只有选定的值.

查看模型

public class CreateViewModel : CreateBindingModel {
    public IEnumerable<SelectListItem> CountryList {get;set;}
}

public class UpdateViewModel : UpdateBindingModel {
    public IEnumerable<SelectListItem> CountryList {get;set;}
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这为您提供了很大的灵活性,但仍然有一些重复的代码(两个视图的视图模型所需的额外信息),可以通过多种方式(根据需求/上下文)进行缓解:

  1. 有一个动作来检索公共数据和使用 @Html.Action("GetCountryList");
  2. 使用相同的View Model aka CreateUpdateViewModelUpdateBindingModel在视图中丢弃额外的属性,但仍然在POST上发布相应的模型.
  3. 将绑定模型作为属性并在特定视图中选择一个或另一个.(更好地使用@Html.EditorFor而不是部分,因此Model Binder将无需对代码进行额外更改即可使用)

控制器操作如下所示:

调节器

[HttpGet]
public ActionResult Create(){
    ViewData.Model = new CreateViewModel();
    return View();
}

[HttpPost]
public RedirectToRouteResult Create(CreateBindingModel binding) {
    // check valid model state and create data
    return RedirectToAction("Index");
}

[HttpGet]
public ActionResult Update(int id) {
    var objectToEdit = service.GetObjectToEdit(id);
    ViewData.Model = new UpdateViewModel(objectToEdit);
    return View();
}

[HttpPost]
public RedirectToRouteResult Update(UpdateBindingModel binding) {
    // check valid model state and update data
    return RedirectToAction("Index");
}
Run Code Online (Sandbox Code Playgroud)

你的意见:

查看

Update.cshtml
<form action="Update">
    @Html.HiddenFor(Model.Id);
    @Html.Partial("EditFieldsPartial")
    <button>delete</button> // no delete button on create.
    <button>create new</button> // you can have a create new instead of update.
</form>

Create.cshtml
<form action="Create">
    @Html.Partial("EditFieldsPartial")
</form>
Run Code Online (Sandbox Code Playgroud)

注意:代码不完整,并且在大多数情况下不使用帮助程序以简洁和清晰.不要复制粘贴:D


Tom*_*mmi 44

你当然可以.

在帖子上,检查您的控制器是否主键值为0然后插入,否则更新.

"创建"和"编辑"视图应相同.

请记住包括:

@Html.HiddenFor(model=>model.ID)
Run Code Online (Sandbox Code Playgroud)

在你看来

例如:

模型:

public class DescriptionModel
{
    [Key]
    public int ID { get; set; }

    public string Description { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

CreateEdit.cshtml:

@model DescriptionModel

@using (Html.BeginForm("CreateEdit"))
{
    @Html.HiddenFor(model=> model.ID)
    @Html.EditorFor(model=> model.Description)
    <input type="submit" value='Submit' />
}
Run Code Online (Sandbox Code Playgroud)

DescriptionModel控制器:

public ActionResult Create()
{
    return View("CreateEdit", new DescriptionModel());
}
public ActionResult Edit(int id)
{
    return View("CreateEdit", db.DescriptionModels.Find(id));
}

// Submit and add or update database
[HttpPost]
public ActionResult CreateEdit(DescriptionModel model)
{
    if (ModelState.IsValid)
    {
       // No id so we add it to database
       if (model.ID <= 0)
       {
           db.DescriptionModels.Add(model);
       }
       // Has Id, therefore it's in database so we update
       else
       {
           db.Entry(model).State = EntityState.Modified;
       }
       db.SaveChanges();
       return RedirectToAction("Index");
    }

    return View(model);
}
Run Code Online (Sandbox Code Playgroud)

  • 我相信这种方法很容易受到过度攻击.例如,黑客可以导航到编辑页面以获取其记录,并修改隐藏字段"DescriptionModel.ID"的值以指向他们不应该访问的另一条记录.当他们发布表单时,它将修改其他记录而不是他们自己的记录.[Bart的回答](http://stackoverflow.com/a/25374200/1515372)概述了解决此安全问题的替代方法. (6认同)
  • @Ifligus您可以使用简单的`if`语句解决安全性问题。类似于(伪代码)`if Model.User!= currentUser然后抛出新的ForbiddenException()`ID,而不是保持两个相对相同的形式。 (2认同)