取消和存储操作的适当路由
Appropriate routing of the actions Cancel and Store
我有一个列出所有自行车的页面 (Bike.cshtml)。单击单个自行车时,我将转到编辑页面 (BikeEdit.cshtml)。在编辑器的底部,我有两个链接。
@Html.ActionLink("Cancel", "Bikes", "Home")
@Html.ActionLink("Update", "Bikes", "Home")
这两种情况都应该返回到列出自行车的页面。显然,在第二个中,我希望将模型对象的更改存储到数据库中。我很想通过像这样发送模型来解决它。
@Html.ActionLink("Cancel", "Bikes", "Home")
@Html.ActionLink("Update", "Bikes", "Home", @Model, null)
不过,我感觉到有更好的方法来处理它。管理自行车查看器控制器的节省有些令人不安。
我能想到的另一种方法是添加一个新动作,BikeSave,并在其中执行保存。但是,返回的视图实例不会基于 Bikes.cshtml,而是 BikeSave.cshtml。我可以想象我可以使用 RedirectToAction 但我不确定。我不想使用 "duct tape".
设计一些东西
所以我摇摇头无法决定...
当用户点击更新按钮时,您应该将表单提交到您的 HttpPost 操作方法,您将在其中更新您的数据库,然后重定向到 Home/Bikes 页面。
假设你的 GET 操作是这样的
public ActionResult BikeEdit(int id)
{
var bikeEditVm=new BikeEditVm { Id=id};
var bikeEntity = db.Bikes.FirstOrDefault(s=>s.Id==id);
if(bikeEntity!=null)
{
bikeEditVm.ModelName=bikeEntity.ModelName;
bikeEditVm.Color=bikeEntity.Color;
return View(bikeEditVm);
}
return View("NotFound"); // return a bike not found view to user
}
其中BikeEditVm
是编辑视图的视图模型,看起来像这样
public class BikeEditVm
{
public int Id {set;get;}
public string ModelName {set;get;}
public string Color {set;get;}
}
在 BikeEditVm 的强类型视图中,您会将所有可编辑字段保存在 form
标签中
@model BikeEditVm
@using(Html.BeginForm())
{
<label>ModelName</label>
@Html.TextBoxFor(s=>s.ModelName)
<label>Color</label>
@Html.TextBoxFor(s=>s.Color)
@Html.HiddenFor(s=>s.Id)
<input type="submit" value="Update" />
}
@Html.ActionLink("Cancel","Bikes","Home")
您将有一个 HttpAction 方法来处理表单发布,您将从数据库中读取现有实体,更新您要更新的相关字段并将其保存回来。
[HttpPost]
public ActionResult BikeEdit(BikeEditVm model)
{
var bikeEntity = db.Bikes.FirstOrDefault(s=>s.Id==model.id);
if(bikeEntity!=null)
{
bikeEntity .ModelName = model.ModelName;
bikeEntity .Color = model.Color;
db.Entry(bikeEntity).State=EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Bikes","Home");
}
return View("NotFound");
}
编辑: 回答 OP 在评论中为未来的读者提出的一些问题。
(1) I tested to skip [HttpPost] and it works still. Should it?
任何更新您的数据的东西都应该是一个 HttpPost method.otherwise,人们可以通过 url(GET 方法)访问您的操作方法并传递表单字段 name-values 并可以尝试更新您的数据。(如果存在,您的授权检查可能会阻止这种情况)
(2) How does your Html.BeginForm() know where to route? I'm using
Html.BeginForm(action, controller).
如果您不向 BeginForm
方法传递任何参数,它会将表单操作值设置为当前 url。例如:如果您在 customer/create GET 操作视图,您的表单将发布到 customer/create。您可以通过使用不同的重载来覆盖此行为,您可以在其中指定不同的操作 method/controller 名称。
(3) If I want a field to be passed up/down but not be
editable/visible, should I use CSS to hide it? It'd be good to have a
control for off-screen storage.
如果您不希望该字段是 editable/visible,请不要将其传递给您的视图。在您的视图模型中只包含您视图中真正需要的那些属性。阅读下一个关于如何防止过度发布的回复。
(4) Is it generally the best idea to have a specialized model for the
view instead of using the one from EF?
是的。如果您使用由您的 ORM 创建的实体 类 在您的操作方法和视图之间传输数据,那么您正在制作一个紧密耦合的解决方案。如果您明天出于任何原因决定不使用 EF 作为数据访问层怎么办?你想去更新你所有的观点吗?您的视图模型特定于视图。因此,只保留视图所需的那些 properties/fields。这也将帮助您 .
我有一个列出所有自行车的页面 (Bike.cshtml)。单击单个自行车时,我将转到编辑页面 (BikeEdit.cshtml)。在编辑器的底部,我有两个链接。
@Html.ActionLink("Cancel", "Bikes", "Home")
@Html.ActionLink("Update", "Bikes", "Home")
这两种情况都应该返回到列出自行车的页面。显然,在第二个中,我希望将模型对象的更改存储到数据库中。我很想通过像这样发送模型来解决它。
@Html.ActionLink("Cancel", "Bikes", "Home")
@Html.ActionLink("Update", "Bikes", "Home", @Model, null)
不过,我感觉到有更好的方法来处理它。管理自行车查看器控制器的节省有些令人不安。
我能想到的另一种方法是添加一个新动作,BikeSave,并在其中执行保存。但是,返回的视图实例不会基于 Bikes.cshtml,而是 BikeSave.cshtml。我可以想象我可以使用 RedirectToAction 但我不确定。我不想使用 "duct tape".
设计一些东西所以我摇摇头无法决定...
当用户点击更新按钮时,您应该将表单提交到您的 HttpPost 操作方法,您将在其中更新您的数据库,然后重定向到 Home/Bikes 页面。
假设你的 GET 操作是这样的
public ActionResult BikeEdit(int id)
{
var bikeEditVm=new BikeEditVm { Id=id};
var bikeEntity = db.Bikes.FirstOrDefault(s=>s.Id==id);
if(bikeEntity!=null)
{
bikeEditVm.ModelName=bikeEntity.ModelName;
bikeEditVm.Color=bikeEntity.Color;
return View(bikeEditVm);
}
return View("NotFound"); // return a bike not found view to user
}
其中BikeEditVm
是编辑视图的视图模型,看起来像这样
public class BikeEditVm
{
public int Id {set;get;}
public string ModelName {set;get;}
public string Color {set;get;}
}
在 BikeEditVm 的强类型视图中,您会将所有可编辑字段保存在 form
标签中
@model BikeEditVm
@using(Html.BeginForm())
{
<label>ModelName</label>
@Html.TextBoxFor(s=>s.ModelName)
<label>Color</label>
@Html.TextBoxFor(s=>s.Color)
@Html.HiddenFor(s=>s.Id)
<input type="submit" value="Update" />
}
@Html.ActionLink("Cancel","Bikes","Home")
您将有一个 HttpAction 方法来处理表单发布,您将从数据库中读取现有实体,更新您要更新的相关字段并将其保存回来。
[HttpPost]
public ActionResult BikeEdit(BikeEditVm model)
{
var bikeEntity = db.Bikes.FirstOrDefault(s=>s.Id==model.id);
if(bikeEntity!=null)
{
bikeEntity .ModelName = model.ModelName;
bikeEntity .Color = model.Color;
db.Entry(bikeEntity).State=EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Bikes","Home");
}
return View("NotFound");
}
编辑: 回答 OP 在评论中为未来的读者提出的一些问题。
(1) I tested to skip [HttpPost] and it works still. Should it?
任何更新您的数据的东西都应该是一个 HttpPost method.otherwise,人们可以通过 url(GET 方法)访问您的操作方法并传递表单字段 name-values 并可以尝试更新您的数据。(如果存在,您的授权检查可能会阻止这种情况)
(2) How does your Html.BeginForm() know where to route? I'm using Html.BeginForm(action, controller).
如果您不向 BeginForm
方法传递任何参数,它会将表单操作值设置为当前 url。例如:如果您在 customer/create GET 操作视图,您的表单将发布到 customer/create。您可以通过使用不同的重载来覆盖此行为,您可以在其中指定不同的操作 method/controller 名称。
(3) If I want a field to be passed up/down but not be editable/visible, should I use CSS to hide it? It'd be good to have a control for off-screen storage.
如果您不希望该字段是 editable/visible,请不要将其传递给您的视图。在您的视图模型中只包含您视图中真正需要的那些属性。阅读下一个关于如何防止过度发布的回复。
(4) Is it generally the best idea to have a specialized model for the view instead of using the one from EF?
是的。如果您使用由您的 ORM 创建的实体 类 在您的操作方法和视图之间传输数据,那么您正在制作一个紧密耦合的解决方案。如果您明天出于任何原因决定不使用 EF 作为数据访问层怎么办?你想去更新你所有的观点吗?您的视图模型特定于视图。因此,只保留视图所需的那些 properties/fields。这也将帮助您