模型在发布时为空

本文关键字:布时 模型 | 更新日期: 2023-09-27 18:00:37

当我提交时,我的模型在发布时是空的。

型号

public QuizModel()
{
    Questions = new List<QuizQuestionModel>();
}
public QuizModel(string quizName)
{
    QuizName = quizName;
    Score = 0;
    IntranetEntities db = new IntranetEntities();
    Quiz quiz = db.Quizs.Where(x => x.Name.Equals(quizName, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
    if (quiz != null)
    {
        IQueryable<Quiz_Question> questions = db.Quiz_Question.Where(x => x.QuizID.Equals(quiz.ID)).OrderBy(x => x.QuestionNo);
        Questions = new List<QuizQuestionModel>();
        foreach (Quiz_Question question in questions)
        {
            QuizQuestionModel q = new QuizQuestionModel();
            q.ID = question.ID;
            q.Question = question.Question;
            q.UserAnswer = null;
            q.SystemAnswer = question.Answer;
            Questions.Add(q);
        }
    }
}
public string QuizName { get; set; }
public List<QuizQuestionModel> Questions { get; set; }
public int Score { get; set; }

控制器

[HttpPost]
public ActionResult OSHAQuiz(Models.QuizModel model)
{
    if (ModelState.IsValid)
    {
        bool passed = false;
        model.Score = model.Questions.Where(x => x.UserAnswer.Equals(x.SystemAnswer, StringComparison.InvariantCultureIgnoreCase)).Count();
        if (!model.Score.Equals(0))
        {
            double percent = model.Score / model.Questions.Count();
            if (percent >= .8)
            {
                passed = true;
            }
        }
        if (passed)
        {
            return View("/Views/Quiz/Passed.cshtml");
        }
        else
        {
            return View("/Views/Quiz/Failed.cshtml");
        }
    }
    else
    {
        return View("/Views/Quiz/Quiz.cshtml", model);
    }
}

查看

@model PAL.Intranet.Models.QuizModel
<script>
    $(document).ready(function () {
        $("input:checked").removeAttr("checked");
    });
</script>
<div class="grid">
    <h2>OSHA Quiz</h2>
    <hr />
    <div class="align-center">
        @using (Html.BeginForm("OSHAQuiz", "Quiz", FormMethod.Post, new { id = "formShowLoading" }))
        {
            @Html.AntiForgeryToken()
            @Html.ValidationSummary(true)
            <div class="row cell">
                <div class="example bg-grayLighter" data-text="Directions">
                    <ul class="simple-list">
                        <li class="align-left">When you have made your selection for all 20 statements, click on the button 'Submit.'</li>
                        <li class="align-left">Mark 'True' or 'False' for each statement.</li>
                        <li class="align-left">You must score 80% (16 correct) to pass.</li>
                        <li class="align-left">You must fill in your full name to receive credit.</li>
                    </ul>
                </div>
            </div>
            <div class="row cell">
                <div class="row cell">
                    <div class="panel" data-role="panel">
                        <div class="heading">
                            <span class="title">Questions</span>
                        </div>
                        <div class="content">
                            <ul class="numeric-list">
                                @foreach (var question in Model.Questions)
                                {
                                    <li>
                                        <table class="table hovered" style="width: 100%;">
                                            <tr>
                                                <td align="left">@question</td>
                                                <td align="right" width="150px">
                                                    <div class="align-center">
                                                        <label class="align-right input-control radio small-check">
                                                            @Html.RadioButtonFor(model => question.UserAnswer, true, new { Name = question.GroupName })
                                                            <span class="check"></span>
                                                            <span class="caption">True</span>
                                                        </label>
                                                        <label class="align-right input-control radio small-check">
                                                            @Html.RadioButtonFor(model => question.UserAnswer, false, new { Name = question.GroupName })
                                                            <span class="check"></span>
                                                            <span class="caption">False</span>
                                                        </label>
                                                    </div>
                                                </td>
                                            </tr>
                                        </table>
                                    </li>
                                }
                            </ul>
                        </div>
                    </div>
                </div>
            </div>
            <div class="row cell">
                <input type="submit" value="Submit" class="button info small-button" />
                <input type="reset" value="Reset" class="button primary small-button" />
            </div>
        }
    </div>
</div>

更新

如果我在QuizName上使用HiddeFor,它会在发布时返回,但模型的其余部分是空的。

模型在发布时为空

在迭代要发布回模型的集合时,不能使用foreach;必须使用带索引的常规for语句,Razor才能生成正确的字段名。

@for (var i = 0; i < Model.Questions.Count(); i++)
{
    ...
    @Html.RadioButtonFor(m => m.Questions[i].UserAnswer)
}

然后,字段将具有Questions[0].UserAnswer形式的名称属性,模型绑定器将识别这些属性并将其适当地绑定到模型。现在,对于foreach,字段名被生成为question.UserAnswer,模型绑定器不知道该如何处理并丢弃它。

此外,FWIW,从模型实体中访问上下文是一个非常糟糕的想法,如果你不注入它,情况会更糟。将该逻辑从实体中移除,转而使用实用程序类或服务。此外,请研究依赖项注入,因为您的上下文是您想要的东西之一,并且每个请求只有一个实例。如果您开始实例化同一上下文的多个实例,将出现问题。

问题是模型绑定将尝试将表单值绑定到模型上的属性。它不会在您的模型上使用带有测验名称的构造函数,而是使用默认构造函数来实例化QuizModel对象。

我会考虑重构这个模型,以删除EntityFramework依赖项,并找到一种新的方法来填充这些值。

在使用完IDisposable对象后,还应该对它们调用Dispose()方法。

我对如何解决这个问题的建议是使用你目前必须帮助呈现你的观点的测验模型(即你的测验问题和每个问题的可能答案)。

为测验提交创建一个单独的ViewModel

public class QuizSubmission
{
  public string QuizName { get;set; }
  public List<QuizQuestionResponse> Responses { get;set; }
}
public class QuizQuestionResponse
{
   public int QuestionId { get;set; }
   public int AnswerId { get;set; }
}

在控制器操作中,您应该绑定到QuizSubmission模型。

[HttpPost]
public ActionResult OSHAQuiz(Models.QuizSubmission model)
{

然后,您将能够执行提交测验所需的任何操作(即数据访问、验证)。

您还需要更新视图,以便Html输入元素具有正确的名称属性,模型绑定可以将每个问题和响应对正确绑定到响应列表中的QuizQuestionResponse项。