繁体   English   中英

模型在发布时为空

[英]Model empty on post

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

模型

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上使用HiddenFor,它确实会在发布时返回,但模型的其余部分为空。

遍历要发布回模型的集合时,不能使用foreach 您必须使用带有索引的常规for语句,以便Razor生成正确的字段名称。

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

然后,您的字段将具有Questions[0].UserAnswer形式的名称属性,modelbinder将识别并适当地绑定到您的模型。 就像您现在拥有的那样,使用foreach ,字段名称将作为question.UserAnswer生成,modelbinder不知道该如何处理并丢弃。

同样,FWIW,从模型实体内部访问您的上下文是一个非常糟糕的主意,甚至如果您不注入它,那就更糟了。 将该逻辑移出您的实体,并改用实用程序类或服务。 另外,请研究依赖项注入,因为上下文是您希望每个请求一个实例的事情之一。 如果开始实例化同一上下文的多个实例, 则会遇到问题。

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

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

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

对于如何解决此问题,我的建议是使用当前必须使用的QuizModel来帮助呈现您的视图(即您的测验问题以及每个问题的可能答案)。

创建一个单独的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项。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM