mvc 提交后 ActionResult 方法中没有数据
mvc No data in ActionResult method after submit
我有一个索引页面,其中有一个部分用于写项目名称,select 从下拉列表中写项目类型。
在其下方我有一个提交按钮,它指向项目控制器中的 ActionResult 方法 Create。
代码:
[更新]
index.cshtml:
@using reqcoll.ViewModels
@model myViewModel
@{
ViewBag.Title = "ReqColl - project";
}
@* First half *@
@using (Html.BeginForm("CreateProject", "Projects"))
{
@Html.AntiForgeryToken()
<div class="top-spacing col-md-12 col-lg-12 col-sm-12">
@RenderTopHalf(Model.modelProject)
</div>
}
@* Second half *@
@using (Html.BeginForm("CreateRequirement", "Projects"))
{
@Html.AntiForgeryToken()
<div class="form-group" id="pnSecondHalf">
@* Requirements list *@
<div class=" col-md-6 col-lg-6 col-sm-12">
@RenderBottomLeftHalf(Model.modelRequirement)
</div>
@* New/Edit requirements panel *@
<div class="col-md-6 col-lg-6 col-sm-12">
@RenderBottomRightHalf(Model.modelRequirement)
</div>
</div>
}
@* ================================================================================= ============= *@
@* Helpers *@
@helper RenderTopHalf(reqcoll.Models.Project project)
{
<div class=" well">
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="row">
@Html.LabelFor(model => project.projectName, htmlAttributes: new { @class = "control-label col-md-2 col-lg-2 col-sm-12" })
<div class="col-md-10 col-lg-10 col-sm-12">
@Html.TextBoxFor(model => project.projectName, htmlAttributes: new { @class = "ProjectNameInput" })
@Html.ValidationMessageFor(model => project.projectName)
</div>
</div>
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="row row-spacing">
@Html.LabelFor(model => project.projectType, htmlAttributes: new { @class = "control-label col-md-2 col-lg-2 col-sm-12" })
<div class="col-md-10 col-lg-10 col-sm-12">
@Html.DropDownListFor(model => project.projectType, new SelectList(
new List<Object>{
new { value = 0 , text = "...Select..." },
new { value = 1 , text = "Windows application" },
new { value = 2 , text = "Web application" },
new { value = 3 , text = "Device application"}
},
"value",
"text",
project.projectType), htmlAttributes: new { @class = "DropDownList" })
@Html.ValidationMessageFor(model => project.projectType)
</div>
<input type="hidden" value="" id="hdProjectID" />
</div>
<div class="row top-spacing col-md-offset-5 col-sm-offset-5">
<div id="pnCreate" class=" col-sm-4 col-md-4 col-lg-4">
<input type="submit" class="btn btn-default" value="Create" />
</div>
<div id="pnEdit" class=" col-sm-4 col-md-4 col-lg-4">
<input type="submit" class="btn btn-default" value="Edit" />
|
<input type="submit" class="btn btn-default" value="Delete" />
</div>
</div>
</div>
}
@helper RenderBottomLeftHalf(reqcoll.Models.Requirement requirement)
{
<div class=" well">
<table class="table">
<tr>
<th>
@if (Model.modelProject.Requirements != null)
{
var m = Model.modelProject;
if (m.Requirements.Count > 0)
{
@Html.DisplayNameFor(model => model.modelProject.Requirements[0].shortDesc)
}
}
else
{
<label class="label label-primary col-sm-12 col-md-6 col-lg-6">No requirements available</label>
}
</th>
<th></th>
</tr>
@if (Model.modelProject.Requirements != null)
{
var m = Model.modelProject;
if (m.Requirements.Count > 0)
{
foreach (var item in Model.modelProject.Requirements)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.shortDesc)
</td>
<td>
@* buttons here*@
@*@Html.ActionLink("E", "Edit", new { id = item.requirementID }) |
@Html.ActionLink("D", "Delete", new { id = item.requirementID })*@
</td>
</tr>
}
}
}
</table>
</div>
}
@helper RenderBottomRightHalf(reqcoll.Models.Requirement requirement)
{
<div class=" well">
@Html.ValidationSummary(true)
<div class="row">
@Html.LabelFor(model => requirement.shortDesc, htmlAttributes: new { @class = "control-label col-md-4 col-lg-4 col-sm-12" })
<div class="col-md-8 col-lg-8 col-sm-12">
@Html.TextBoxFor(model => requirement.shortDesc, htmlAttributes: new { @class = "RequirementShortDesc" })
@Html.ValidationMessageFor(model => requirement.shortDesc)
</div>
</div>
@Html.ValidationSummary(true)
<div class="row row-spacing">
@Html.LabelFor(model => requirement.longDesc, htmlAttributes: new { @class = "control-label col-md-4 col-lg-4 col-sm-12" })
<div class="col-md-8 col-lg-8 col-sm-12 RequirementLongDesc">
@Html.EditorFor(model => requirement.longDesc)
@Html.ValidationMessageFor(model => requirement.longDesc)
</div>
</div>
@Html.ValidationSummary(true)
<div class="row row-spacing">
@Html.LabelFor(model => requirement.priorityCode, htmlAttributes: new { @class = "control-label col-md-4 col-lg-4 col-sm-12" })
<div class="col-md-8 col-lg-8 col-sm-12">
@foreach (var value in Enum.GetValues(requirement.priorityCode.GetType()))
{
<div class="control-label col-sm-5 col-md-5 col-lg-5">
@Html.RadioButtonFor(m => requirement.priorityCode, value)
@Html.Label(value.ToString())
</div>
}
@Html.ValidationMessageFor(model => requirement.priorityCode)
</div>
</div>
<input type="hidden" value="" id="hdRequirementID" />
<div class="row top-spacing col-md-offset-5 col-sm-offset-5">
<div id="pnReqCreate" class=" col-sm-12 col-md-6 col-lg-6">
@* submit button here *@
@*@Html.ActionLink("Add", "Add", "Requirement", new { @class = "btn btn-default btnSize" })*@
</div>
<div id="pnReqEdit" class=" col-sm-12 col-md-6 col-lg-6">
@* submit buttons here *@
@*@Html.ActionLink("Edit", "Edit", "Requirement", new { @class = "btn btn-default btnSize" })
@Html.ActionLink("Delete", "Delete", "Requirement", new { @class = "btn btn-default btnSize" })*@
</div>
</div>
</div>
}
@section Scripts {
<script>
$(function () {
var pID = $('#hdProjectID').val();
if (pID != null) {
if (pID.length > 0) {
$('#pnEdit').show();
$('#pnCreate').hide();
$('#pnSecondHalf').show();
} else {
$('#pnEdit').hide();
$('#pnCreate').show();
$('#pnSecondHalf').hide();
}
} else {
$('#pnEdit').hide();
$('#pnCreate').show();
$('#pnSecondHalf').hide();
}
var rID = $('#hdRequirementID').val();
if (rID != null) {
if (rID.length > 0) {
$('#pnReqEdit').show();
$('#pnReqCreate').hide();
} else {
$('#pnReqEdit').hide();
$('#pnReqCreate').show();
}
} else {
$('#pnReqEdit').hide();
$('#pnReqCreate').show();
}
});
</script>
@Scripts.Render("~/bundles/jqueryval")
}
视图模型:
using reqcoll.Models;
namespace reqcoll.ViewModels
{
public class myViewModel
{
public Project modelProject;
public Requirement modelRequirement;
}
}
控制器:
using System.Web.Mvc;
using reqcoll.Models;
using reqcoll.ViewModels;
namespace reqcoll.Controllers
{
public class ProjectsController : Controller
{
private myContext db = new myContext();
// GET: Projects
public ActionResult Index()
{
// allow more than one model to be used in the view
var vm = new myViewModel()
{
modelProject = new Project() { projectName = "test", projectType = 1 },
modelRequirement = new Requirement() { requirementID = -1 },
};
return View(vm);
}
[HttpPost]
[ValidateAntiForgeryToken]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateProject(myViewModel vm)
{
if (vm != null)
{
var ab = Request.Form;
// key 1: __RequestVerificationToken
// key 2: project.projectName
// key 3: project.projectType
if (ModelState.IsValid)
{
Project project = vm.modelProject;
// db.Project.Add(project.Item1);
// db.SaveChanges();
// return RedirectToAction("Index");
}
}
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
[原创]
@using (Html.BeginForm("Create", "Projects"))
{
@Html.AntiForgeryToken()
<div class="top-spacing col-md-12 col-lg-12 col-sm-12">
<div class=" well">
@Html.ValidationSummary(true)
<div class="row">
@Html.LabelFor(model => model.Item1.projectName, htmlAttributes: new { @class = "control-label col-md-2 col-lg-2 col-sm-12" })
<div class="col-md-10 col-lg-10 col-sm-12">
@Html.TextBoxFor(model => model.Item1.projectName, htmlAttributes: new { @class = "ProjectNameInput" })
@Html.ValidationMessageFor(model => model.Item1.projectName)
</div>
</div>
@Html.ValidationSummary(true)
<div class="row row-spacing">
@Html.LabelFor(model => model.Item1.projectType, htmlAttributes: new { @class = "control-label col-md-2 col-lg-2 col-sm-12" })
<div class="col-md-10 col-lg-10 col-sm-12">
@Html.DropDownListFor(model => model.Item1.projectType, new SelectList(
new List<Object>{
new { value = 0 , text = "...Select..." },
new { value = 1 , text = "Windows application" },
new { value = 2 , text = "Web application" },
new { value = 3 , text = "Device application"}
},
"value",
"text",
0), htmlAttributes: new { @class = "DropDownList" })
@Html.ValidationMessageFor(model => model.Item1.projectType)
</div>
<input type="hidden" value="" id="hdProjectID" />
</div>
<div class="row top-spacing col-md-offset-5 col-sm-offset-5">
<div id="pnCreate" class=" col-sm-4 col-md-4 col-lg-4">
<input type="submit" class="btn btn-default" value="Create" />
</div>
<div id="pnEdit" class=" col-sm-4 col-md-4 col-lg-4">
<input type="submit" class="btn btn-default" value="Edit" />
|
<input type="submit" class="btn btn-default" value="Delete" />
</div>
</div>
</div>
</div>
}
项目控制器:
private myContext db = new myContext();
// GET: Projects
public ActionResult Index()
{
// allow more than one model to be used in the view
return View(new Tuple<Project, Requirement, Priority>(new Project(), new Requirement(), new Priority()));
}
[HttpPost]
[ValidateAntiForgeryToken]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Include = "projectName,projectType")] Project project)
{
if (ModelState.IsValid)
{
db.Project.Add(project);
db.SaveChanges();
return RedirectToAction("Index");
}
return RedirectToAction("Index");
}
所以当提交按钮被点击时,调用了ActionResult Create,但是ModelState是无效的,没有用户输入的信息。
我做错了什么?
您的模型看起来像复杂对象,因为您正在使用模型。Item1.projectName 和模型。Item1.projectType,但在操作方法中您试图直接获取值,这是错误的。
[更新代码]
随着新代码的发布,对您的模型的这种快速更正将允许它从您的角度正确绑定:
namespace reqcoll.ViewModels
{
public class myViewModel
{
public Project project;
public Requirement requirement;
}
}
[原创]
尽管使用 Tuple<> 类型而不是定义 class 来封装要传递给视图的数据。您仍然可以通过在您的视图中创建一个助手来实现您想要的。
@helper RenderMyProject(Project project) {
...
@Html.TextBoxFor(x=> project.projectType)
...
}
然后,你会调用这个助手
@RenderMyProject(model.Item1)
有什么区别?
输入的名称将会改变。而不是将 [Item1.projectType] 在响应对象内部发布到您的控制器,它看起来像 [project.projectType],它将自动映射到您的项目参数。
找到问题了。
我添加了{get;将 myViewModel 中的 set;} 设置到两个模型,然后它就起作用了。
所以:
using reqcoll.Models;
namespace reqcoll.ViewModels
{
public class myViewModel
{
public Project Project { get; set; }
public Requirement Requirement { get; set; }
}
}
我有一个索引页面,其中有一个部分用于写项目名称,select 从下拉列表中写项目类型。
在其下方我有一个提交按钮,它指向项目控制器中的 ActionResult 方法 Create。
代码: [更新] index.cshtml:
@using reqcoll.ViewModels
@model myViewModel
@{
ViewBag.Title = "ReqColl - project";
}
@* First half *@
@using (Html.BeginForm("CreateProject", "Projects"))
{
@Html.AntiForgeryToken()
<div class="top-spacing col-md-12 col-lg-12 col-sm-12">
@RenderTopHalf(Model.modelProject)
</div>
}
@* Second half *@
@using (Html.BeginForm("CreateRequirement", "Projects"))
{
@Html.AntiForgeryToken()
<div class="form-group" id="pnSecondHalf">
@* Requirements list *@
<div class=" col-md-6 col-lg-6 col-sm-12">
@RenderBottomLeftHalf(Model.modelRequirement)
</div>
@* New/Edit requirements panel *@
<div class="col-md-6 col-lg-6 col-sm-12">
@RenderBottomRightHalf(Model.modelRequirement)
</div>
</div>
}
@* ================================================================================= ============= *@
@* Helpers *@
@helper RenderTopHalf(reqcoll.Models.Project project)
{
<div class=" well">
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="row">
@Html.LabelFor(model => project.projectName, htmlAttributes: new { @class = "control-label col-md-2 col-lg-2 col-sm-12" })
<div class="col-md-10 col-lg-10 col-sm-12">
@Html.TextBoxFor(model => project.projectName, htmlAttributes: new { @class = "ProjectNameInput" })
@Html.ValidationMessageFor(model => project.projectName)
</div>
</div>
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="row row-spacing">
@Html.LabelFor(model => project.projectType, htmlAttributes: new { @class = "control-label col-md-2 col-lg-2 col-sm-12" })
<div class="col-md-10 col-lg-10 col-sm-12">
@Html.DropDownListFor(model => project.projectType, new SelectList(
new List<Object>{
new { value = 0 , text = "...Select..." },
new { value = 1 , text = "Windows application" },
new { value = 2 , text = "Web application" },
new { value = 3 , text = "Device application"}
},
"value",
"text",
project.projectType), htmlAttributes: new { @class = "DropDownList" })
@Html.ValidationMessageFor(model => project.projectType)
</div>
<input type="hidden" value="" id="hdProjectID" />
</div>
<div class="row top-spacing col-md-offset-5 col-sm-offset-5">
<div id="pnCreate" class=" col-sm-4 col-md-4 col-lg-4">
<input type="submit" class="btn btn-default" value="Create" />
</div>
<div id="pnEdit" class=" col-sm-4 col-md-4 col-lg-4">
<input type="submit" class="btn btn-default" value="Edit" />
|
<input type="submit" class="btn btn-default" value="Delete" />
</div>
</div>
</div>
}
@helper RenderBottomLeftHalf(reqcoll.Models.Requirement requirement)
{
<div class=" well">
<table class="table">
<tr>
<th>
@if (Model.modelProject.Requirements != null)
{
var m = Model.modelProject;
if (m.Requirements.Count > 0)
{
@Html.DisplayNameFor(model => model.modelProject.Requirements[0].shortDesc)
}
}
else
{
<label class="label label-primary col-sm-12 col-md-6 col-lg-6">No requirements available</label>
}
</th>
<th></th>
</tr>
@if (Model.modelProject.Requirements != null)
{
var m = Model.modelProject;
if (m.Requirements.Count > 0)
{
foreach (var item in Model.modelProject.Requirements)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.shortDesc)
</td>
<td>
@* buttons here*@
@*@Html.ActionLink("E", "Edit", new { id = item.requirementID }) |
@Html.ActionLink("D", "Delete", new { id = item.requirementID })*@
</td>
</tr>
}
}
}
</table>
</div>
}
@helper RenderBottomRightHalf(reqcoll.Models.Requirement requirement)
{
<div class=" well">
@Html.ValidationSummary(true)
<div class="row">
@Html.LabelFor(model => requirement.shortDesc, htmlAttributes: new { @class = "control-label col-md-4 col-lg-4 col-sm-12" })
<div class="col-md-8 col-lg-8 col-sm-12">
@Html.TextBoxFor(model => requirement.shortDesc, htmlAttributes: new { @class = "RequirementShortDesc" })
@Html.ValidationMessageFor(model => requirement.shortDesc)
</div>
</div>
@Html.ValidationSummary(true)
<div class="row row-spacing">
@Html.LabelFor(model => requirement.longDesc, htmlAttributes: new { @class = "control-label col-md-4 col-lg-4 col-sm-12" })
<div class="col-md-8 col-lg-8 col-sm-12 RequirementLongDesc">
@Html.EditorFor(model => requirement.longDesc)
@Html.ValidationMessageFor(model => requirement.longDesc)
</div>
</div>
@Html.ValidationSummary(true)
<div class="row row-spacing">
@Html.LabelFor(model => requirement.priorityCode, htmlAttributes: new { @class = "control-label col-md-4 col-lg-4 col-sm-12" })
<div class="col-md-8 col-lg-8 col-sm-12">
@foreach (var value in Enum.GetValues(requirement.priorityCode.GetType()))
{
<div class="control-label col-sm-5 col-md-5 col-lg-5">
@Html.RadioButtonFor(m => requirement.priorityCode, value)
@Html.Label(value.ToString())
</div>
}
@Html.ValidationMessageFor(model => requirement.priorityCode)
</div>
</div>
<input type="hidden" value="" id="hdRequirementID" />
<div class="row top-spacing col-md-offset-5 col-sm-offset-5">
<div id="pnReqCreate" class=" col-sm-12 col-md-6 col-lg-6">
@* submit button here *@
@*@Html.ActionLink("Add", "Add", "Requirement", new { @class = "btn btn-default btnSize" })*@
</div>
<div id="pnReqEdit" class=" col-sm-12 col-md-6 col-lg-6">
@* submit buttons here *@
@*@Html.ActionLink("Edit", "Edit", "Requirement", new { @class = "btn btn-default btnSize" })
@Html.ActionLink("Delete", "Delete", "Requirement", new { @class = "btn btn-default btnSize" })*@
</div>
</div>
</div>
}
@section Scripts {
<script>
$(function () {
var pID = $('#hdProjectID').val();
if (pID != null) {
if (pID.length > 0) {
$('#pnEdit').show();
$('#pnCreate').hide();
$('#pnSecondHalf').show();
} else {
$('#pnEdit').hide();
$('#pnCreate').show();
$('#pnSecondHalf').hide();
}
} else {
$('#pnEdit').hide();
$('#pnCreate').show();
$('#pnSecondHalf').hide();
}
var rID = $('#hdRequirementID').val();
if (rID != null) {
if (rID.length > 0) {
$('#pnReqEdit').show();
$('#pnReqCreate').hide();
} else {
$('#pnReqEdit').hide();
$('#pnReqCreate').show();
}
} else {
$('#pnReqEdit').hide();
$('#pnReqCreate').show();
}
});
</script>
@Scripts.Render("~/bundles/jqueryval")
}
视图模型:
using reqcoll.Models;
namespace reqcoll.ViewModels
{
public class myViewModel
{
public Project modelProject;
public Requirement modelRequirement;
}
}
控制器:
using System.Web.Mvc;
using reqcoll.Models;
using reqcoll.ViewModels;
namespace reqcoll.Controllers
{
public class ProjectsController : Controller
{
private myContext db = new myContext();
// GET: Projects
public ActionResult Index()
{
// allow more than one model to be used in the view
var vm = new myViewModel()
{
modelProject = new Project() { projectName = "test", projectType = 1 },
modelRequirement = new Requirement() { requirementID = -1 },
};
return View(vm);
}
[HttpPost]
[ValidateAntiForgeryToken]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateProject(myViewModel vm)
{
if (vm != null)
{
var ab = Request.Form;
// key 1: __RequestVerificationToken
// key 2: project.projectName
// key 3: project.projectType
if (ModelState.IsValid)
{
Project project = vm.modelProject;
// db.Project.Add(project.Item1);
// db.SaveChanges();
// return RedirectToAction("Index");
}
}
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
[原创]
@using (Html.BeginForm("Create", "Projects"))
{
@Html.AntiForgeryToken()
<div class="top-spacing col-md-12 col-lg-12 col-sm-12">
<div class=" well">
@Html.ValidationSummary(true)
<div class="row">
@Html.LabelFor(model => model.Item1.projectName, htmlAttributes: new { @class = "control-label col-md-2 col-lg-2 col-sm-12" })
<div class="col-md-10 col-lg-10 col-sm-12">
@Html.TextBoxFor(model => model.Item1.projectName, htmlAttributes: new { @class = "ProjectNameInput" })
@Html.ValidationMessageFor(model => model.Item1.projectName)
</div>
</div>
@Html.ValidationSummary(true)
<div class="row row-spacing">
@Html.LabelFor(model => model.Item1.projectType, htmlAttributes: new { @class = "control-label col-md-2 col-lg-2 col-sm-12" })
<div class="col-md-10 col-lg-10 col-sm-12">
@Html.DropDownListFor(model => model.Item1.projectType, new SelectList(
new List<Object>{
new { value = 0 , text = "...Select..." },
new { value = 1 , text = "Windows application" },
new { value = 2 , text = "Web application" },
new { value = 3 , text = "Device application"}
},
"value",
"text",
0), htmlAttributes: new { @class = "DropDownList" })
@Html.ValidationMessageFor(model => model.Item1.projectType)
</div>
<input type="hidden" value="" id="hdProjectID" />
</div>
<div class="row top-spacing col-md-offset-5 col-sm-offset-5">
<div id="pnCreate" class=" col-sm-4 col-md-4 col-lg-4">
<input type="submit" class="btn btn-default" value="Create" />
</div>
<div id="pnEdit" class=" col-sm-4 col-md-4 col-lg-4">
<input type="submit" class="btn btn-default" value="Edit" />
|
<input type="submit" class="btn btn-default" value="Delete" />
</div>
</div>
</div>
</div>
}
项目控制器:
private myContext db = new myContext();
// GET: Projects
public ActionResult Index()
{
// allow more than one model to be used in the view
return View(new Tuple<Project, Requirement, Priority>(new Project(), new Requirement(), new Priority()));
}
[HttpPost]
[ValidateAntiForgeryToken]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Include = "projectName,projectType")] Project project)
{
if (ModelState.IsValid)
{
db.Project.Add(project);
db.SaveChanges();
return RedirectToAction("Index");
}
return RedirectToAction("Index");
}
所以当提交按钮被点击时,调用了ActionResult Create,但是ModelState是无效的,没有用户输入的信息。
我做错了什么?
您的模型看起来像复杂对象,因为您正在使用模型。Item1.projectName 和模型。Item1.projectType,但在操作方法中您试图直接获取值,这是错误的。
[更新代码]
随着新代码的发布,对您的模型的这种快速更正将允许它从您的角度正确绑定:
namespace reqcoll.ViewModels
{
public class myViewModel
{
public Project project;
public Requirement requirement;
}
}
[原创]
尽管使用 Tuple<> 类型而不是定义 class 来封装要传递给视图的数据。您仍然可以通过在您的视图中创建一个助手来实现您想要的。
@helper RenderMyProject(Project project) {
...
@Html.TextBoxFor(x=> project.projectType)
...
}
然后,你会调用这个助手
@RenderMyProject(model.Item1)
有什么区别?
输入的名称将会改变。而不是将 [Item1.projectType] 在响应对象内部发布到您的控制器,它看起来像 [project.projectType],它将自动映射到您的项目参数。
找到问题了。
我添加了{get;将 myViewModel 中的 set;} 设置到两个模型,然后它就起作用了。
所以:
using reqcoll.Models;
namespace reqcoll.ViewModels
{
public class myViewModel
{
public Project Project { get; set; }
public Requirement Requirement { get; set; }
}
}