asp.net-mvc ASP.NET MVC - 使用相同的表单来创建和编辑
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/399914/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ASP.NET MVC - using the same form to both create and edit
提问by iasksillyquestions
Whats the best practice approach to creating a form that is used to both create new models and edit existing models?
创建用于创建新模型和编辑现有模型的表单的最佳实践方法是什么?
Are there any tutorials that people can point me in the direction of?
是否有任何教程可以让我指明方向?
采纳答案by Craig Stuntz
Do not use the same controller action.New = HTTP POST; edit = HTTP PUT, so that's two different things. Both actions can and should be on the same controller, though.
不要使用相同的控制器操作。新 = HTTP POST; 编辑 = HTTP PUT,所以这是两件不同的事情。不过,这两个动作可以而且应该在同一个控制器上。
I like the idea of using a user control for common features (e.g., editors), and wrapping that in action-specific views for stuff which should only appear on new or edit, but not both.
我喜欢将用户控件用于通用功能(例如,编辑器),并将其包装在特定于操作的视图中,以便只出现在 new 或 edit 中,但不能同时出现在两者中。
回答by Mariano Desanze
NerdDinnerwill reallyshow the way.
NerdDinner将真正指明方向。
Create.aspx
创建.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
编辑.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
晚餐表格.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>
<% } %>
Take into account that this form is using Html.EditorForModel(), which is an innovative method for generating all the fields at once, and you have to study its disadvantages before using it. But you can easily take the rest of the example to separate your common form from the create and edit views.
考虑到这个表格正在使用Html.EditorForModel(),这是一次生成所有字段的创新方法,您必须在使用之前研究其缺点。但是您可以轻松地利用示例的其余部分将您的通用表单与创建和编辑视图分开。
Finally you can view the controller code hereif you are interested.
回答by E Rolnicki
回答by Dmitry Sikorsky
Assumptions
假设
This is good for the user to see different URLs for different actions in the browser. For example '/pages/create' and '/pages/edit/1'.
This is good for developer to have only one action+view pair both to create and edit pages because they are usually very similar. (Also, this is good to have one controller per entity.)
这有利于用户在浏览器中看到不同操作的不同 URL。例如“/pages/create”和“/pages/edit/1”。
这对开发人员来说只有一个操作+视图对来创建和编辑页面是有好处的,因为它们通常非常相似。(此外,每个实体有一个控制器也很好。)
Solution
解决方案
Default routes registration is '{controller}/{action}/{id}' We can add two more rules beforethis one:
默认路由注册是 '{controller}/{action}/{id}' 我们可以在这之前再添加两条规则:
{controller}/create (should point to 'CreateOrEdit' action)
{controller}/create(应该指向“CreateOrEdit”动作)
{controller}/edit/{id} (should point to 'CreateOrEdit' action too)
{controller}/edit/{id}(也应该指向“CreateOrEdit”动作)
We can have now something like this:
我们现在可以有这样的事情:
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 }
);
}
So now both create and edit requests will be handled by 'CreateOrEdit' action. Others will go the default way.
所以现在创建和编辑请求都将由“CreateOrEdit”操作处理。其他人将采用默认方式。
Next what we should do is to add 'CreateOrEdit' action for HttpGet and HttpPost in our controller:
接下来我们应该做的是在我们的控制器中为 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);
}
And the last we have to add view named 'CreateOrEdit'. We can user 'this.Model.Id == null' there to know whether we create or edit.
最后我们必须添加名为“CreateOrEdit”的视图。我们可以在那里使用 'this.Model.Id == null' 来知道我们是创建还是编辑。
Result
结果
Now we don't have duplicate code and can have obvious urls like this:
现在我们没有重复的代码,并且可以有如下明显的 url:
/pages (to see all pages)
/pages(查看所有页面)
/pages/create (to create new page)
/pages/create(创建新页面)
/pages/edit/1 (to edit existing page)
/pages/edit/1(编辑现有页面)
/pages/delete/1 (to delete existing page)
/pages/delete/1(删除现有页面)
I hope it will help someone!
我希望它会帮助某人!
回答by Chtiwi Malek
this is not always the best practice because it depends on the case, here's how i did it
这并不总是最佳实践,因为这取决于具体情况,这是我的做法
1/i combined the controller actions for create and edit
1/我结合了创建和编辑的控制器动作
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/i combined the edit and create views into one view i call Creedit
2/我将编辑和创建视图合并到一个视图中,我称之为 Creedit
// if you need to display something unique to a create view
// just check if the Model is null
@if(Model==null){
}
so i have 1 view and 2 actions (1 post and 1 get) instead of 2 views and 4 action.
所以我有 1 个视图和 2 个操作(1 个帖子和 1 个获取)而不是 2 个视图和 4 个操作。
回答by Perpetualcoder
It could be (should be IMO) one controller but different controller actions. Also make sure you have proper HTTP verbs associated with appropriate action. Follow the tutorial posted by E Rolnicki and you will be on your way!
它可以是(应该是 IMO)一个控制器但不同的控制器动作。还要确保您有与适当操作相关联的正确 HTTP 动词。按照 E Rolnicki 发布的教程进行操作,您就可以开始了!
Happy Coding!!
快乐编码!!
回答by Trevor de Koekkoek
I have a system that I think works pretty well. In my shared views I have 2 generic forms, Edit.aspx and New.aspx
我有一个我认为运行良好的系统。在我的共享视图中,我有 2 个通用表单 Edit.aspx 和 New.aspx
Then in my specific view folder I have a control named EditItems.ascx
然后在我的特定视图文件夹中,我有一个名为 EditItems.ascx 的控件
In my edit form I have the form tags and specific buttons for edit and in the new form I have the form tags and specific buttons for new. In each I have Html.RenderPartial("EditItems.ascx")
在我的编辑表单中,我有表单标签和用于编辑的特定按钮,而在新表单中,我有表单标签和用于新建的特定按钮。在每个我有 Html.RenderPartial("EditItems.ascx")
This way your user control can be strongly typed and yet you are reusing the look and feel of the edit and new pages.
通过这种方式,您的用户控件可以是强类型的,但您可以重用编辑和新页面的外观和感觉。
Now in some cases, your new page might have a different layout than the Edit page. In that case just add "Edit.aspx" to your specific view folder.
现在,在某些情况下,您的新页面的布局可能与“编辑”页面不同。在这种情况下,只需将“Edit.aspx”添加到您的特定视图文件夹。
I find this gives me the best combination of reuse while still allowing full customization should I need it. And as for controller actions, yes they should be separate actions.
我发现这为我提供了最佳的重用组合,同时在我需要时仍然允许完全自定义。至于控制器动作,是的,它们应该是单独的动作。
回答by Serge Wautier
If the entity has some kind of internal private key (e.g. an "id" member that is always > 0), you can use /Edit/0 instead of /Create
如果实体具有某种内部私钥(例如始终 > 0 的“id”成员),您可以使用 /Edit/0 而不是 /Create
回答by ChrisFox
I use something like
我使用类似的东西
[HttpGet]
public ActionResult EntityEdit(Guid id)
{
return View();
}
and
和
[HttpGet]
public ActionResult EntityCreate()
{
return View("EntityEdit");
}
That seems to work OK.
这似乎工作正常。
回答by Keith Williams
I put the form itself in a user control - say, Views/Shared/WidgetForm.ascx. I put all form fields in this user control, but NOT the form tags themselves.
我将表单本身放在用户控件中 - 例如,Views/Shared/WidgetForm.ascx。我将所有表单字段都放在这个用户控件中,但不是表单标签本身。
The views, say Views/Widgets/New.aspx and Views/Widgets/Edit.aspx, have the form tags in them and all the "surroundings" - instructions for filling in the form, page title, etc etc. Then they include the user control inside the form tags.
视图,比如 Views/Widgets/New.aspx 和 Views/Widgets/Edit.aspx,包含表单标签和所有“环境”——填写表单、页面标题等的说明。然后它们包括表单标签内的用户控件。
The user control simply takes a Widget object, and displays a form based on the results. Putting sensible defaults in new Widget options therefore becomes important, but you're doing that anyway, right? ;)
用户控件只需要一个 Widget 对象,并根据结果显示一个表单。因此,在新的 Widget 选项中设置合理的默认值变得很重要,但无论如何您都在这样做,对吗?;)

