ASP.NET MVC – 使用相同的表单来创build和编辑

创build用于创build新模型和编辑现有模型的表单的最佳实践方法是什么?

有什么教程可以让人指导我吗?

不要使用相同的控制器操作。 新= HTTP PUT; 编辑= HTTP POST,所以这是两个不同的东西。 虽然这两种行为都可以并且应该在同一个控制器上。

我喜欢使用普通function的用户控件(例如编辑器),并将其包含在特定于操作的视图中,以便只显示在新的或编辑的内容上,但不能同时显示。

NerdDinner将真正展现出来。

Create.aspx

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<NerdDinner.Models.Dinner>" MasterPageFile="~/Views/Shared/Site.Master" %> <asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server"> Host a Nerd Dinner </asp:Content> <asp:Content ID="Create" ContentPlaceHolderID="MainContent" runat="server"> <h2>Host a Dinner</h2> <% Html.RenderPartial("DinnerForm"); %> </asp:Content> 

Edit.aspx

 <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<NerdDinner.Models.Dinner>" MasterPageFile="~/Views/Shared/Site.Master" %> <asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server"> Edit: <%:Model.Title %> </asp:Content> <asp:Content ID="Edit" ContentPlaceHolderID="MainContent" runat="server"> <h2>Edit Dinner</h2> <% Html.RenderPartial("DinnerForm"); %> </asp:Content> 

DinnerForm.ascx

 <%@ Language="C#" Inherits="System.Web.Mvc.ViewUserControl<NerdDinner.Models.Dinner>" %> <script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script> <script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script> <script src="/Scripts/MicrosoftMvcValidation.js" type="text/javascript"></script> <% Html.EnableClientValidation(); %> <%: Html.ValidationSummary("Please correct the errors and try again.") %> <% using (Html.BeginForm()) { %> <fieldset> <div id="dinnerDiv"> <%:Html.EditorForModel() %> <p> <input type="submit" value="Save" /> </p> </div> <div id="mapDiv"> <%: Html.EditorFor(m => m.Location) %> </div> </fieldset> <% } %> 

考虑到这种forms是使用Html.EditorForModel() ,这是一个创造性的方法,一次产生所有的领域,你必须研究其使用之前的缺点。 但是,您可以轻松地使用示例的其余部分将常用表单与创build和编辑视图分开。

最后,如果您有兴趣,可以在这里查看控制器代码 。

斯科特·古(Scott Gu)将会展现出自己

假设

  1. 这对于用户在浏览器中查看不同动作的不同URL是很好的。 比如'/ pages / create'和'/ pages / edit / 1'。

  2. 这对于开发人员来说只有一个动作+视图对才能创build和编辑页面,因为它们通常非常相似。 (而且,每个实体都有一个控制器是很好的。)

默认路由注册是“{controller} / {action} / {id}”我们可以之前添加两条规则:

{controller} / create(应该指向'CreateOrEdit'动作)

{controller} / edit / {id}(也应该指向'CreateOrEdit'动作)

我们现在可以有这样的东西:

 public static void RegisterRoutes(RouteCollection routes) { routes.MapRoute( name: "Create", url: "{controller}/create", defaults: new { controller = "Default", action = "CreateOrEdit" } ); routes.MapRoute( name: "Edit", url: "{controller}/edit/{id}", defaults: new { controller = "Default", action = "CreateOrEdit" } ); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Default", action = "Index", id = UrlParameter.Optional } ); } 

所以现在创build和编辑请求都将通过“CreateOrEdit”操作来处理。 其他人将采取默认的方式。

接下来我们应该做的是在我们的控制器中为HttpGet和HttpPost添加“CreateOrEdit”动作:

 [HttpGet] public ActionResult CreateOrEdit(int? id) { return this.View(new CreateOrEditViewModelBuilder(this).Build(id)); } [HttpPost] public ActionResult CreateOrEdit(CreateOrEditViewModel сreateOrEditViewModel) { if (this.ModelState.IsValid) { Page page = new CreateOrEditViewModelMapper(this).Map(сreateOrEditViewModel); if (сreateOrEditViewModel.Id == null) this.UnitOfWork.GetRepository<IPageRepository>().Create(page); else this.UnitOfWork.GetRepository<IPageRepository>().Edit(page); this.UnitOfWork.Save(); return this.RedirectToAction("Index"); } return this.View(сreateOrEditViewModel); } 

最后,我们必须添加名为“CreateOrEdit”的视图。 我们可以用'this.Model.Id == null'来知道我们是否创build或编辑。

结果

现在我们没有重复的代码,可以有这样的明显的url:

/页面(查看所有页面)

/ pages / create(创build新页面)

/ pages / edit / 1(编辑现有页面)

/ pages / delete / 1(删除现有页面)

我希望这会帮助别人!

它可以是(应该是IMO)一个控制器,但不同的控制器动作。 还要确保你有正确的HTTP动词与适当的行动相关联。 按照E Rolnicki发布的教程,你将会在你的路上!

快乐编码!

这并不总是最好的做法,因为它取决于案件,这是我是如何做到的

1 / i结合了用于创build和编辑的控制器动作

 public PartialViewResult Creedit(string id = null) { if (id == null) { // Create new record (this is the view in Create mode) return PartialView(); } else { // Edit record (view in Edit mode) Client x = db.ClientSet.Find(id); if (x == null) { return PartialView("_error"); } // ... return PartialView(x); } } [HttpPost] [ValidateAntiForgeryToken] public ActionResult Creedit(Client x) { if (x.id == null) { // insert new record } else { // update record } } 

2 /我把编辑和创build视图合并成一个视图,我称之为Creedit

 // if you need to display something unique to a create view // just check if the Model is null @if(Model==null){ } 

所以我有1个视图和2个动作(1个post和1个获得)而不是2个视图和4个动作。

我把表单本身放在一个用户控件中 – 比如Views / Shared / WidgetForm.ascx。 我把所有的表单字段放在这个用户控件中,但不是表单标签本身。

Views / Widgets / New.aspx和Views / Widgets / Edit.aspx等视图都有表单标签,所有的“环境” – 填写表单,页面标题等的指示。用户在表单标签内控制。

用户控件只需要一个Widget对象,并根据结果显示一个表单。 因此,在新的Widget选项中设置合理的默认值就变得很重要,但是你仍然这样做,对吧? ;)

我有一个系统,我觉得工作得很好。 在我的共享视图中,我有2个通用forms,Edit.aspx和New.aspx

然后在我的具体视图文件夹我有一个名为EditItems.ascx的控件

在我的编辑窗体中,我有窗体标签和特定的编辑button,在新窗体中,我有窗体标签和新的特定button。 在每个我有Html.RenderPartial(“EditItems.ascx”)

这样,您的用户控件可以被强制input,但是您正在重新使用编辑和新页面的外观。

现在,在某些情况下,您的新页面可能与编辑页面的布局不同。 在这种情况下,只需将“Edit.aspx”添加到您的特定视图文件夹。

我发现这给了我重用的最佳组合,同时仍然允许完全定制,如果我需要它。 至于pipe制员的行动,是的,他们应该是单独的行动。

如果实体具有某种内部私钥(例如总是大于0的“id”成员),则可以使用/ Edit / 0而不是/ Create

我使用类似的东西

 [HttpGet] public ActionResult EntityEdit(Guid id) { return View(); } 

 [HttpGet] public ActionResult EntityCreate() { return View("EntityEdit"); } 

这似乎工作确定。