【问题标题】:ASP.NET MVC Form Values not being set on Post未在 Post 上设置 ASP.NET MVC 表单值
【发布时间】:2010-09-02 10:49:56
【问题描述】:

我有一个名为 Problem 的模型对象:

[Table(Name = "Problems")]
public class Problem
{
    [HiddenInput(DisplayValue = false)]
    [Column(IsPrimaryKey = true, IsDbGenerated = true, AutoSync = AutoSync.OnInsert)]
    public int ProblemId { get; set; }

    [Display(ResourceType = typeof(Resources.Resources), Name = "TablePersonStudentName")]
    [Column] public int StudentId { get; set; }

    [Display(ResourceType = typeof(Resources.Resources), Name = "TableCommunicationTypesName")]
    [Column] public int CommunicationTypeId { get; set; }

    [Display(ResourceType = typeof(Resources.Resources), Name = "TableProblemTypeName")]
    [Column] public int ProblemTypeId { get; set; }

    [Display(ResourceType = typeof(Resources.Resources), Name = "TableMitigatingCircumstanceLevelName")]
    [Column] public int MitigatingCircumstanceLevelId { get; set; }

    [Display(ResourceType = typeof(Resources.Resources), Name = "TableProblemDate")]
    [Column] public DateTime? DateTime { get; set; }

    [Display(ResourceType = typeof(Resources.Resources), Name = "TableProblemOutline")]
    [Column] public string Outline { get; set; }

    [Display(ResourceType = typeof(Resources.Resources), Name = "TableProblemFile")]
    [Column] public byte[] MitigatingCircumstanceFile { get; set; }

    [Display(ResourceType = typeof(Resources.Resources), Name = "TableProblemAbsentFrom")]
    [Column] public DateTime? AbsentFrom { get; set; }

    [Display(ResourceType = typeof(Resources.Resources), Name = "TableProblemAbsentUntil")]
    [Column] public DateTime? AbsentUntil { get; set; }

    [Display(ResourceType = typeof(Resources.Resources), Name = "TableProblemRequestedFollowUp")]
    [Column] public DateTime? RequestedFollowUp { get; set; }

    public CommunicationType CommunicationType { get; set; }

    public MitigatingCircumstanceLevel MitigatingCircumstanceLevel { get; set; }

    public ProblemType ProblemCategory { get; set; }

    public ICollection<ProblemCommunication> ProblemCommunications { get; set; }

    public ICollection<AssessmentExtension> AssessmentExtensions { get; set; }

    public ICollection<User> Users { get; set; }

}

由于此模型包含来自其他数据库表的大量对象,因此我在视图中使用 viewModel 来使用下拉列表:

public class ProblemViewModel
{
    public Problem Problem { get; set; }
    public SelectList Students { get; set; }
    public SelectList CommunicationType { get; set; }
    public SelectList MitigatingCircumstanceLevel { get; set; }
    public SelectList ProblemType { get; set; }
    public MultiSelectList ProblemUsers { get; set; }

    public ProblemViewModel(Problem problem, ISqlStudentRepository sqlStudentRepository, 
        ISqlCommunicationTypeRepository sqlCommunicationTypeRepository, ISqlMitigatingCircumstanceLevelRepository sqlMitigatingCircumstanceRepository,
        ISqlProblemTypeRepository sqlProblemTypeRepository, ISqlUserRepository sqlUserRepository,
        string username)
    {
        this.Problem = problem;
        this.Students = new SelectList(sqlStudentRepository.Students.ToList(), "StudentId", "FirstName");
        this.CommunicationType = new SelectList(sqlCommunicationTypeRepository.CommunicationTypes.ToList(), "CommunicationTypeId", "Name");
        this.MitigatingCircumstanceLevel = new SelectList(sqlMitigatingCircumstanceRepository.MitigatingCircumstanceLevels.ToList(), "MitigatingCircumstanceLevelId", "Name");
        this.ProblemType = new SelectList(sqlProblemTypeRepository.ProblemTypes.ToList(), "ProblemTypeId", "TypeName");
        this.ProblemUsers = new MultiSelectList(sqlUserRepository.Users.Where(s => s.UserName != username).ToList(), "UserId", "UserName");
    }
}

这是在导航到问题/创建控制器方法时生成的:

public ViewResult Create()
    {
        string username = User.Identity.Name;

        return View("Edit", new ProblemViewModel(new Problem(), sqlStudentRepository, 
            sqlCommunicationTypeRepository, sqlMitigatingCircumstanceRepository,
            sqlProblemTypeRepository, sqlUserRepository, username));
    }

这是 ascx 视图:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<BournemouthUniversity.WebUI.Models.ProblemViewModel>" %>
        <div class="editor-field">
            <%: Html.HiddenFor(model => model.Problem.ProblemId)%>
            <%: Html.ValidationMessageFor(model => model.Problem.ProblemId)%>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.Problem.StudentId) %>
        </div>
        <div class="editor-field">
            <%: Html.DropDownListFor(model => model.Problem.StudentId, Model.Students)%>
            <%: Html.ValidationMessageFor(model => model.Problem.StudentId)%>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.Problem.CommunicationTypeId)%>
        </div>
        <div class="editor-field">
            <%: Html.DropDownListFor(model => model.Problem.CommunicationTypeId, Model.CommunicationType)%>
            <%: Html.ValidationMessageFor(model => model.Problem.CommunicationTypeId)%>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.Problem.ProblemTypeId)%>
        </div>
        <div class="editor-field">
            <%: Html.DropDownListFor(model => model.Problem.ProblemTypeId, Model.ProblemType)%>
            <%: Html.ValidationMessageFor(model => model.Problem.ProblemTypeId)%>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.Problem.MitigatingCircumstanceLevelId)%>
        </div>
        <div class="editor-field">
            <%: Html.DropDownListFor(model => model.Problem.MitigatingCircumstanceLevelId, Model.MitigatingCircumstanceLevel)%>
            <%: Html.ValidationMessageFor(model => model.Problem.MitigatingCircumstanceLevelId)%>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.Problem.DateTime)%>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.Problem.DateTime, new { @class = "datePicker" })%>
            <%: Html.ValidationMessageFor(model => model.Problem.DateTime)%>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.Problem.Outline)%>
        </div>
        <div class="editor-field">
            <%: Html.TextAreaFor(model => model.Problem.Outline, 6, 70, new { maxlength = 255 })%>
            <%: Html.ValidationMessageFor(model => model.Problem.Outline)%>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.Problem.AbsentFrom)%>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.Problem.AbsentFrom, new { @class = "datePicker" })%>
            <%: Html.ValidationMessageFor(model => model.Problem.AbsentFrom)%>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.Problem.AbsentUntil)%>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.Problem.AbsentUntil, new { @class = "datePicker" })%>
            <%: Html.ValidationMessageFor(model => model.Problem.AbsentUntil)%>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.Problem.RequestedFollowUp)%>
        </div>
        <div class="editor-field">
            <%: Html.TextBoxFor(model => model.Problem.RequestedFollowUp, new { @class = "dateTimePicker" })%>
            <%: Html.ValidationMessageFor(model => model.Problem.RequestedFollowUp)%>
        </div>

        <div class="editor-label">
            <%: Html.LabelFor(model => model.Problem.Users)%>
        </div>
        <div class="editor-field">
            <%: Html.ListBoxFor(model => model.Problem.Users, Model.ProblemUsers, new { @class = "multiselect" })%>
            <%: Html.ValidationMessageFor(model => model.Problem.Users)%>
        </div>

        <p>
            <input type="submit" class="button" value="Save" />
        </p>

<% } %>

但是,当我提交表单时,输入了 [HttpPost] 编辑控制器操作,但大多数值都为 null...

[HttpPost]
    public ActionResult Edit(Problem problemValues)
    {
        try
        {
            MembershipUser myObject = Membership.GetUser();
            String UserId = myObject.ProviderUserKey.ToString();

            Problem problem = problemValues.ProblemId == 0
                ? new Problem()
                : sqlProblemRepository.Problems(UserId).First(p => p.ProblemId == problemValues.ProblemId);
            TryUpdateModel(problem);

            if (ModelState.IsValid)
            {
                sqlProblemRepository.SaveProblem(problem);
                TempData["message"] = problem.ProblemId + " has been saved.";

                if (Request.IsAjaxRequest())
                {
                    return Json(problem);
                }

                return RedirectToAction("Details", "Student", new { problem.StudentId });
            }
            else
                return View(problem);
        }
        catch (Exception ex)
        {
            if (Request.IsAjaxRequest())
            {
                return Json(null);
            }
            else
            {
                TempData["message"] = "Record Not Found.";
                return RedirectToAction("Index");
            }
        }
    }

对此的任何想法将不胜感激,它似乎发生在我有下拉列表的大多数表单上,但是我不明白为什么所有值都为空,即使是非下拉字段。

提前谢谢...

乔纳森

【问题讨论】:

  • 在深入挖掘之前,我注意到你正在将你的 repo 传递给一个视图模型......这是一种代码味道
  • 感谢您的建议。我对 ASP.NET MVC 很陌生。我刚刚制定了一个解决方案来让它工作。我想我应该在控制器中填充 SelectLists 所需的列表,然后将它们传递给 viewModel。

标签: asp.net asp.net-mvc-2


【解决方案1】:

我建议您将存储库与模型分开。这样,您传递给视图的所有内容就是模型。 View 和 ViewModel 都不需要任何存储库。它的工作方式是控制器使用存储库来获取模型并将此模型传递给视图:

public ViewResult Create()
{
    string username = User.Identity.Name;
    Problem model = someRepository.FetchModel(username);
    ProblemViewModel viewModel = someMapper.ConvertToViewModel(model);

    return View("Edit", viewModel);
}

以及提交操作:

[HttpPost]
public ViewResult Create(ProblemViewModel viewModel)
{
    // viewModel will contain all the fields that you have corresponding
    // inputs in the View
    ...
}

【讨论】:

  • 如果我将控制器操作头更改为 [HttpPost] public ViewResult Edit(ProblemViewModel viewModel) 我得到:没有为此对象定义无参数构造函数。
  • 是的,这很正常。您必须删除使用所有存储库的构造函数,因为它不再具有任何意义。
  • 虽然这确实提供了“重写所有内容以使其更像 X”的解决方案,但这不是您发布的问题的解决方案......
  • 感谢您的帮助。该解决方案确实有效,但是我发现将视图模型发送到视图更容易,但在视图中使用 E Rolnicki 解决方案将问题对象返回到编辑操作而不是视图模型对象。我已经从我的视图模型中取出了存储库,现在在控制器中获取数据,然后调用视图模型构造函数。感谢您的建议感谢它!
  • @E Rolnicki,SO 不仅是为了提供问题的解决方案,而且是为了提倡良好的做法并将存储库传递给视图,并且使用非强类型的助手绝对不是一个好习惯。
【解决方案2】:

如果您检查生成的 html,我想您会发现表单字段使用点表示法..基本上回发 model.Problem 而不仅仅是 Problem...这就是您的...呃....问题

编辑 我没有很好地解释这一点,我认为....您的 html 字段应该发回属性,这些属性将映射到操作接受的模型,在这种情况下,操作需要一个问题模型....但是,您的 html 字段正在发回一个有问题的模型......而不是问题。

【讨论】:

  • 我检查了我的 HTML,但我认为我没有模型。问题: 都是问题。
  • 恰恰相反,那是你的问题。为了正确映射,这些字段应该只是 ProblemId、StudentId、CommunicationTypeId 等...而不是 Problem.XXXX
  • 解决方案是使用其他 Htmlhelper 重载,因此 model.Problem.ProblemId)%> 您将使用
  • 感谢您的帮助。虽然 Darin Dimitrov 的解决方案确实有效,但将视图模型发送到视图要容易得多,但在视图中使用您的解决方案来返回问题对象而不是视图模型对象。所以我参考了你们两个的建议。我已经从我的视图模型中取出了存储库,现在在控制器中获取数据,然后调用视图模型构造函数。感谢您的建议感谢它!
  • 指出我可以只看 html 引导我找到正确的解决方案(facepalm 时刻)。
【解决方案3】:

我认为您需要将编辑操作的签名更改为

[HttpPost]
public ActionResult Edit(int problemId, Problem problemValues)
{
.
.
}

看来你和这里提到的MVC Custom ViewModel and auto binding有同样的问题

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-09
    • 1970-01-01
    • 2015-04-20
    • 2013-06-19
    相关资源
    最近更新 更多