简体   繁体   English

模型在发布时为空

[英]Model empty on post

When I submit, my model is empty on post. 当我提交时,我的模型在发布时是空的。

Model 模型

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; }

Controller 控制者

[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);
    }
}

View 视图

@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>

UPDATE 更新

if I use HiddenFor on QuizName, it does come back over on post but the rest of the model is empty. 如果我在QuizName上使用HiddenFor,它确实会在发布时返回,但模型的其余部分为空。

When iterating over a collection that you want to post back to your model, you can't use foreach ; 遍历要发布回模型的集合时,不能使用foreach you must use a regular for statement with indexing in order for Razor to generate the correct field names. 您必须使用带有索引的常规for语句,以便Razor生成正确的字段名称。

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

Then, your fields will have name attributes in the form of Questions[0].UserAnswer , which the modelbinder will recognize and bind appropriately to your model. 然后,您的字段将具有Questions[0].UserAnswer形式的名称属性,modelbinder将识别并适当地绑定到您的模型。 As you have it now, with the foreach , the field name is being generated as question.UserAnswer , which the modelbinder has no idea what to do with and discards. 就像您现在拥有的那样,使用foreach ,字段名称将作为question.UserAnswer生成,modelbinder不知道该如何处理并丢弃。

Also, FWIW, accessing your context from within your model entity is a hugely bad idea, and even worse if you're not injecting it. 同样,FWIW,从模型实体内部访问您的上下文是一个非常糟糕的主意,甚至如果您不注入它,那就更糟了。 Move that logic out of your entity and utilize a utility class or service instead. 将该逻辑移出您的实体,并改用实用程序类或服务。 Also, look into dependency injection, as your context is one of those things that you want one and only one instance of per request. 另外,请研究依赖项注入,因为上下文是您希望每个请求一个实例的事情之一。 If you start instantiating multiple instances of the same context, you will have problems. 如果开始实例化同一上下文的多个实例, 则会遇到问题。

The problem is model binding is going to attempt to bind your form values to properties on your model. 问题是模型绑定将试图将表单值绑定到模型上的属性。 It will not use the constructor on your model that takes the quiz name, it will use the default constructor to instantiate the QuizModel object. 它不会使用带有测验名称的模型上的构造函数,它将使用默认构造函数实例化QuizModel对象。

I would consider refactoring this model to remove your EntityFramework dependency and find a new way to populate those values. 我会考虑重构此模型以删除您的EntityFramework依赖关系,并找到一种填充这些值的新方法。

You should also call the Dispose() method on IDisposable objects when you're done using them. 使用完IDisposable对象后,还应该调用它们的Dispose()方法。

My suggestion for how to solve this problem would be to use the QuizModel you currently have to help render your view (ie Your quiz questions and possible answer for each question). 对于如何解决此问题,我的建议是使用当前必须使用的QuizModel来帮助呈现您的视图(即您的测验问题以及每个问题的可能答案)。

Create a seperate ViewModel for quiz submission 创建一个单独的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; }
}

In your controller action, you should be binding to a QuizSubmission model. 在控制器操作中,您应该绑定到QuizSubmission模型。

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

Then you'll be able to perform any actions you need for that quiz submission (ie. data access, validation ). 然后,您将能够执行提交测验所需的任何操作(即,数据访问,验证)。

You'll also need to update your view so that your Html input elements have the correct name attributes that model binding can correctly bind each question and response pair to a QuizQuestionResponse item in your Responses list. 您还需要更新视图,以便您的HTML输入元素具有正确的名称属性,模型绑定可以将每个问题和响应对正确地绑定到“响应”列表中的QuizQuestionResponse项。

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

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