C# 第一次发布后,隐藏字段的值错误
我有一个视图,用户可以使用HTML表单记录在活动上花费的时间。因此,该视图循环遍历所有活动的列表,并为每个活动生成一个日志时间表单(包含在_LogTime部分视图中)。从索引视图传递到局部视图的唯一信息是ActivityId,它以隐藏形式放置。其余所需信息由用户通过提供 我遇到的问题是,一旦我提交了其中一个表单,所有表单的隐藏字段都设置为我刚刚提交的表单的ActivityId。值得注意的是,当页面第一次加载时(在我提交任何表单之前),隐藏字段是正确的,当我第一次提交表单时,正确的活动会被记录时间(其他活动都不会错误地记录时间)。但之后的任何表单提交都只会记录我第一次提交表单的活动的时间 知道这是怎么回事吗?为什么所有隐藏字段都设置为相同的ActivityId?为什么只有在第一篇文章之后?如果您需要任何问题的澄清,请告诉我 型号:C# 第一次发布后,隐藏字段的值错误,c#,html,asp.net-mvc,C#,Html,Asp.net Mvc,我有一个视图,用户可以使用HTML表单记录在活动上花费的时间。因此,该视图循环遍历所有活动的列表,并为每个活动生成一个日志时间表单(包含在_LogTime部分视图中)。从索引视图传递到局部视图的唯一信息是ActivityId,它以隐藏形式放置。其余所需信息由用户通过提供 我遇到的问题是,一旦我提交了其中一个表单,所有表单的隐藏字段都设置为我刚刚提交的表单的ActivityId。值得注意的是,当页面第一次加载时(在我提交任何表单之前),隐藏字段是正确的,当我第一次提交表单时,正确的活动会被记录时间
public class Activity
{
public int ActivityId { get; set; }
public string Name { get; set; }
}
public class UserActivity
{
public int UserId { get; set; }
public int ActivityId { get; set; }
public int Duration { get; set; }
public DateTime Date { get; set; }
}
观点:
// Index View
@foreach (Activity activity in Model)
{
@Html.Partial("_LogTime", new UserActivity(activity.ActivityId))
}
// _LogTime Partial View
@using (Html.BeginForm())
{
<fieldset>
@Html.HiddenFor(model => model.ActivityId)
@Html.EditorFor(model => model.Duration)
@Html.EditorFor(model => model.Date)
<input type="submit" value="LOG TIME" />
</fieldset>
}
我从不在控制器中使用全局变量。 我宁愿把我所有隐藏的值,也包括foreach局部视图中的值,都放在表单中 这样,您可以传递整个列表,然后再添加一个。 现在,我认为您传递了一个空行,并将最后一个添加到该行 当然,可以在post函数中设置断点
@using (Html.BeginForm())
{
// Index View
@foreach (Activity activity in Model)
{
@Html.Partial("_LogTime", new UserActivity(activity.ActivityId))
}
// _LogTime Partial View
<fieldset>
@Html.HiddenFor(model => model.ActivityId)
@Html.EditorFor(model => model.Duration)
@Html.EditorFor(model => model.Date)
<input type="submit" value="LOG TIME" />
</fieldset>
}
@使用(Html.BeginForm())
{
//索引视图
@foreach(模型中的活动)
{
@Html.Partial(“_LogTime”,新用户活动(activity.ActivityId))
}
//_LogTime局部视图
@Html.HiddenFor(model=>model.ActivityId)
@EditorFor(model=>model.Duration)
@EditorFor(model=>model.Date)
}
您遇到的问题是,html助手方法会自动使用同名的post变量更新表单元素。这些值存储在ModelState中。解决此问题的一种方法是从ModelState中删除有问题的条目
另一个可能的修复方法是改为重定向
[HttpPost]
public ActionResult Index(UserActivity activity)
{
if (ModelState.IsValid)
{
_db.UserActivities.Add(activity);
_db.SaveChanges();
}
// Remove the ActivityId from your ModelState before returning the View.
ModelState.Remove("ActivityId")
return View(_db.Activities.ToList());
}
从下面的注释可以看出,使用Remove方法可能表明应用程序的流程存在更深层的问题。在这一点上,我同意埃里克的观点。正如他所指出的,重新设计应用程序的流程可能是一项耗时的任务
当遇到问题指示的行为时,如果有一种方法可以在不修改ModelState的情况下解决问题,那么这将是首选的解决方案。一个恰当的例子可能是不止一个元素受到此问题的影响
为了完整起见,这里有一个替代解决方案:
[HttpPost]
public ActionResult Index(UserActivity activity)
{
if (ModelState.IsValid)
{
_db.UserActivities.Add(activity);
_db.SaveChanges();
}
return RedirectToAction("Index");
}
在让我的批评者闭嘴的最后,这是他无法想出的改写
// Index View
@using (Html.BeginForm())
{
@for (var i = 0; i < Model.Count; i++)
{
<div>
@Html.HiddenFor(model => model[i].ActivityId)
@Html.EditorFor(model => model[i].Duration)
@Html.EditorFor(model => model[i].Date)
</div>
}
<input type="submit" value="LOG TIME ENTRIES" />
}
// Controller Post Method
[HttpPost]
public ActionResult Index(List<UserActivity> activities)
{
if (ModelState.IsValid)
{
foreach( var activity in activities )
{
var first = _db.UserActivities
.FirstOrDefault(row => row.ActivityId == activity.ActivityId );
if ( first == null ) {
_db.UserActivities.Add(activity);
} else {
first.Duration = activity.Duration;
first.Date = activity.Date;
}
}
_db.SaveChanges();
return RedirectToAction("index");
}
// when the ModelState is invalid, we want to
// retain posted values and display errors.
return View(_db.Activities.ToList());
}
//索引视图
@使用(Html.BeginForm())
{
@对于(var i=0;imodel[i].ActivityId)
@EditorFor(model=>model[i].Duration)
@Html.EditorFor(model=>model[i].Date)
}
}
//控制岗位法
[HttpPost]
公共行动结果索引(列出活动)
{
if(ModelState.IsValid)
{
foreach(活动中的var活动)
{
var first=_db.UserActivities
.FirstOrDefault(行=>row.ActivityId==activity.ActivityId);
if(first==null){
_db.UserActivities.Add(活动);
}否则{
first.Duration=活动.Duration;
first.Date=activity.Date;
}
}
_db.SaveChanges();
返回操作(“索引”);
}
//当ModelState无效时,我们希望
//保留发布的值并显示错误。
返回视图(_db.Activities.ToList());
}
在发布这样的代码块时,请添加解释。不是真的,这只是代码,请解释您所做的更改以及原因。@erik我不同意。假设你有一个更好的答案,而不是投反对票。在请求的编辑中,我还提到了另一个选项。@B2K-您可以随意不同意,这不会改变他的代码将生成无效html(具有相同ID的多个项目)的事实。你只是在治疗症状。解决这个问题需要完全重写他的代码,我不打算这么做。您不必从ModelState中删除项。如果你是,那么这是一个不同问题的症状,你只是在掩盖它。修复真正的问题。@ErikFunkenbusch请告诉我,如果Microsoft从未打算使用Remove方法,为什么要在ModelState中添加Remove方法。它们还提供ModelState.Clear命令。这两种方法都不推荐。它们可以在应用程序需要时使用。
// Index View
@using (Html.BeginForm())
{
@for (var i = 0; i < Model.Count; i++)
{
<div>
@Html.HiddenFor(model => model[i].ActivityId)
@Html.EditorFor(model => model[i].Duration)
@Html.EditorFor(model => model[i].Date)
</div>
}
<input type="submit" value="LOG TIME ENTRIES" />
}
// Controller Post Method
[HttpPost]
public ActionResult Index(List<UserActivity> activities)
{
if (ModelState.IsValid)
{
foreach( var activity in activities )
{
var first = _db.UserActivities
.FirstOrDefault(row => row.ActivityId == activity.ActivityId );
if ( first == null ) {
_db.UserActivities.Add(activity);
} else {
first.Duration = activity.Duration;
first.Date = activity.Date;
}
}
_db.SaveChanges();
return RedirectToAction("index");
}
// when the ModelState is invalid, we want to
// retain posted values and display errors.
return View(_db.Activities.ToList());
}