【问题标题】:Binding in Razor returns null (OnPostAsync)Razor 中的绑定返回 null (OnPostAsync)
【发布时间】:2020-08-24 13:05:45
【问题描述】:

在下面的代码中,我们QuestionViewModel 中的所有值都是空的。任何想法我在绑定方面做错了什么?

cs 文件:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using VerityLearn.DataAccess;
using VerityLearn.Domain;
using VerityLearn.DataAccess.UOW;
using VerityLearn.WebUI.ViewModels;

namespace VerityLearn.WebUI.Pages.Questions
{
    [Authorize]
    public class StudentQuestionsModel : PageModel
    {
        private readonly SignInManager<VerityUser> _signInManager;
        private readonly UserManager<VerityUser> _userManager;
        private readonly IStudentQuesionsUOW _studentQuesionsUOW;

        private readonly VerityLearn.DataAccess.VerityContext _context;


        public StudentQuestionsModel(
            VerityContext context,
            SignInManager<VerityUser> signInManager,
            UserManager<VerityUser> userMrg,
            IStudentQuesionsUOW studentQuesionsUOW
        )
        {
            _context = context;
            _signInManager = signInManager;
            _userManager = userMrg;
            _studentQuesionsUOW = studentQuesionsUOW;
        } // end public StudentQuestionsModel(VerityContext context, SignInManager<VerityUser> signInManager, UserManager<VerityUser> userMrg)

        #region User Properties
        public VerityUser VerityUser { get; set; }
        //[TempData]
        //public string UserId { get; set; }
        public Student Student { get; set; }
        public Prospect Prospect { get; set; }
        public Parent Parent { get; set; }
        public ExamUserViewModel ExamUserViewModel { get; set; }
        #endregion // User Properties

        public DateTime DateStarted { get; set; }

        public Exam Exam { get; set; }

        [TempData]
        public int ExamId { get; set; }

        ExamQuestion ExamQuestion { get; set; }

        public List<ExamQuestion> ExamQuestions { get; set; }

        [TempData]
        public int NbrOfExamQuestions { get; set; }

        public ExamViewModel ExamViewModel { get; set; }

        [TempData]
        public int QuestionNdx { get; set; }

        [BindProperty]
        public QuestionViewModel QuestionViewModel { get; set; }

        [ViewData]
        public string Message { get; set; }

        [BindProperty]
        public Question Question { get; set; }

        public async Task OnGetAsync(int? examId, int? questionNdx)
        {
            Message = string.Empty;

            if (_signInManager.IsSignedIn(HttpContext.User))
            {
                string email = HttpContext.User.Identity.Name;
                VerityUser = await _studentQuesionsUOW.GetVerityUser(email);
                //UserId = VerityUser.Id.ToString();
                // TODO: Setup priorities of setting Student, Prospect and Parent properties, might involve Enrollments 4/30/2020
                //Student = await _context.Students.Where(s => s.UserId == VerityUser.Id).FirstOrDefaultAsync<Student>();
                //Prospect = await _context.Prospects.Where(p => p.UserId == VerityUser.Id).FirstOrDefaultAsync<Prospect>();
                //Parent = await _context.Parents.Where(p => p.UserId == VerityUser.Id).FirstOrDefaultAsync<Parent>();
                DateStarted = DateTime.Now;

                if ((examId != null) && (examId.Value > 0))
                {

                   ExamId = examId.Value;
                    Exam = await _context.Exams.Where(e => e.ExamId == examId)
                        .Include(e => e.Course).ThenInclude(c => c.Subject).FirstOrDefaultAsync<Exam>();
                    if (Exam != null)
                    {

                        ExamUserViewModel = new ExamUserViewModel
                        {
                            ExamUserId = 0,
                            ExamId = Exam.ExamId,
                            TimeStarted = DateTime.Now,
                            Status = ExamUserStatus.InProgress,
                            StudentId = VerityUser.StudentId,
                            ProspectId = VerityUser.ProspectId,
                            ParentId = VerityUser.ParentId
                        };
                        // TODO: If this is a new ExamUser, we must insert it to VerityLearnDB2.ExamUsers

                        if (NbrOfExamQuestions == 0)
                        {
                            ExamQuestions = await _context.ExamQuestions
                                .Where(eq => eq.ExamId == examId)
                                .ToListAsync<ExamQuestion>();
                            NbrOfExamQuestions = ExamQuestions.Count;
                            TempData.Keep("NbrOfExamQuestions");
                        } // endif (NbrOfExamQuestions == 0)

                        if ((questionNdx == null) || (questionNdx.Value == 0))
                        {
                            questionNdx = 1;
                        } // endif ((questionNdx == null) || (questionNdx.Value == 0))
                        QuestionNdx = questionNdx.Value;
                        TempData.Keep("QuestionNdx");

                        ExamQuestion = await _context.ExamQuestions
                            .Include(eq => eq.Question)
                            .ThenInclude(q => q.Options)
                            .Where(eq => eq.ExamQuestionOrder == questionNdx)
                            .FirstOrDefaultAsync<ExamQuestion>();

                        QuestionViewModel = new QuestionViewModel
                        {
                            QuestionId = ExamQuestion.QuestionId,
                            ExamQuestionOrder = ExamQuestion.ExamQuestionOrder,
                            QuestionText = ExamQuestion.Question.QuestionText,
                            IsSingleSelection = ExamQuestion.Question.IsSingleSelection,
                            Options = new List<OptionViewModel>()
                        };

                        ExamViewModel = new ExamViewModel
                        {
                            ExamId = Exam.ExamId,
                            ExamName = Exam.ExamName,
                            Questions = new List<QuestionViewModel>()
                        };

                        ExamViewModel.Questions.Add(QuestionViewModel);
                        ExamViewModel.ExamUserViewModel = ExamUserViewModel;

                        List<AnswerOption> answerOptions = _context.AnswerOptions
                            .Where(ao => ao.QuestionId == ExamQuestion.QuestionId)
                            .ToList<AnswerOption>();
                        foreach (AnswerOption ao in answerOptions)
                        {
                            OptionViewModel ovm = new OptionViewModel
                            {
                                OptionId = ao.OptionId,
                                OptionText = ao.OptionText,
                                IsCorrect = ao.IsCorrect
                            };
                            ovm.UserExamOptionViewModel = new UserExamOptionViewModel
                            {
                                UserExamOptionId = ExamUserViewModel.ExamUserId,
                                UserExamId = 0,
                                OptionId = ao.OptionId,
                                IsSelected = false
                            };
                            QuestionViewModel.Options.Add(ovm);
                        } 

                    }
                    else
                    {
                        Message = String.Format("Error: Exam with Identifier, {0}, was not found.", examId);
                    } 
                } 
                else
                {
                    Message = String.Format("Error: Exam with Identifier, {0}, was not found.", examId);
                } 

            }
            else
            {
                Message = "Error: Login is required.";
            }

        } 


        public async Task<IActionResult> OnPostAsync(QuestionViewModel QuestionViewModel)
        {
            var t = QuestionViewModel;
            if (!ModelState.IsValid)
            {
                return Page();
            }

            _context.Attach(Question).State = EntityState.Modified;

            try
            {
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {

            }

            return RedirectToPage("./Index");

        } 
    } 
} 

cshtml文件:

@page "{examId:int?}"
@model VerityLearn.WebUI.Pages.Questions.StudentQuestionsModel
@{
    ViewData["Title"] = "StudentQuestions";
}

@if (String.IsNullOrEmpty(@Model.Message))
{
    <div class="row" style="background-color: #5D2685; color: #FFFF80;">
        <div class="col-md-6">
            <h4>Exam: @Html.DisplayFor(model => model.Exam.ExamName)</h4>
        </div>
        <div class="col-md-6">
            <h4>Course: @Html.DisplayFor(model => model.Exam.Course.CourseName)</h4>
        </div>
    </div>
    <br />
    <br />

    <div>
        <h4>Question</h4>
        <hr />

        <form method="post">

            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input type="hidden" asp-for="Question.QuestionId" />
            <div class="form-group">
                <label asp-for="Question.QuestionText" class="control-label"></label>
                <input asp-for="Question.QuestionText" class="form-control" />
                <span asp-validation-for="Question.QuestionText" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Question.KeyToAnswer" class="control-label"></label>
                <input asp-for="Question.KeyToAnswer" class="form-control" />
                <span asp-validation-for="Question.KeyToAnswer" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Question.IsSingleSelection" class="control-label"></label>
                <input asp-for="Question.IsSingleSelection" class="form-control" />
                <span asp-validation-for="Question.IsSingleSelection" class="text-danger"></span>
            </div>



            <label asp-for="QuestionViewModel.QuestionText" class="control-label"></label>

            @if (Model.QuestionViewModel.IsSingleSelection.Value)
            {
                <p>Select the correct option.</p>

                @foreach (OptionViewModel opt in Model.QuestionViewModel.Options)
                {
                    <input type="radio" name="option" value="@opt.UserExamOptionViewModel.IsSelected"><label for=" @opt.OptionText">&nbsp;&nbsp; @opt.OptionText </label><br />
                }
            }
            else
            {
                <p>Select the correct options (More than one).</p>
                @foreach (OptionViewModel opt in Model.QuestionViewModel.Options)
                {
                    <input type="checkbox" name="option" value="@opt.UserExamOptionViewModel.IsSelected"><label for=" @opt.OptionText">&nbsp;&nbsp;  @opt.OptionText </label><br />
                }
            }

            @{
                var prevDisabled = (Model.QuestionNdx <= 1) ? "disabled" : "";
                var nextDisabled = (Model.QuestionNdx >= Model.NbrOfExamQuestions) ? "disabled" : "";
            }

            <button type="submit" asp-route-questionIndex="@(Model.QuestionNdx - 1)" class="btn btn-primary @prevDisabled">Previous</button>
            <button type="submit" asp-route-questionIndex="@(Model.QuestionNdx + 1)" class="btn btn-primary @nextDisabled">Next</button>

            <div class="form-group">
                <input type="submit" value="Save" class="btn btn-primary" />
            </div>
        </form>

    </div>

}
else
{
<div class="row" style="background-color: #5D2685; color: #FFFF80;">
    <div class="col-md-6">
        <h4>@Model.Message</h4>
    </div>
</div>
}

更新(2020 年 5 月 11 日):

我将视图简化如下:

                @foreach(OptionViewModel opt in Model.QuestionViewModel.Options)
            {
                optionIndex++;

                @Html.RadioButtonFor(model => model.QuestionViewModel.Options[optionIndex].OptionText, @opt.OptionText);
                @opt.OptionText<br />
            }

我看到了 4 个选项,但都被选中了。我希望一次只能选择一个单选按钮。我还是点击下一步

我现在看到选项文本已绑定。问题:如何判断选择了哪一个?

【问题讨论】:

  • 请在视图中显示您正在使用的模型类型...问题是类型是传递给您的操作方法的类型。
  • 添加了@HoomanBahreini。如果需要任何其他信息,请告诉我

标签: asp.net-mvc razor razor-pages


【解决方案1】:

问题是您使用的是复杂模型,但您的 HTML 并未表明该模型很复杂。我创建了一个demo 来强调这个问题:

这里Student 包含AddressList&lt;Subject&gt;(它是复杂模型)

public class Subject 
{
    public string SubjectName { get; set; }
}

public class Address
{
    public string StreetAddress { get; set; }
}

public class Student
{
    public string Name { get; set; }
    public Address HomeAddress { get; set; }
    public List<Subject> Subjects { get; set; }
}

在表单中显示复杂模型时,需要在 html 输入标记中使用整个模型,这样 ASP.NET MVC ModelBinder 知道如何将 HTML 输入绑定到服务器 -侧面模型。

上面的演示有 3 个输入,我使用的是 HTML.TextBoxFor,它是 older equivalentasp-for Tag Helper。

输入1:

@Html.TextBoxFor(model => model.Name) 

生成以下 HTML:

<input id="Name" name="Name" type="text" value="John Smith">

模型绑定器使用name并将上述输入绑定到Student.Name

输入 2

@Html.TextBoxFor(model => model.HomeAddress.StreetAddress) 

生成以下 HTML:

<input id="HomeAddress_StreetAddress" name="HomeAddress.StreetAddress" type="text" value="some address">

这里模型绑定器知道这个输入应该绑定到Student.HomeAddress.StreetAddress,因为这就是输入名称所表示的

输入 3

@Html.TextBoxFor(model => model.Subjects[0].SubjectName) 

生成以下 HTML:

<input id="Subjects_0__SubjectName" name="Subjects[0].SubjectName" type="text" value="Math">

模型绑定器会将上述输入绑定到Student.Subjects[0].SubjectName

请参阅this article 了解更多信息。


在您的示例中,Model Binder 无法知道 option 属于 QuestionViewModel.Options,因为您没有在输入名称中指明它:

<input type="checkbox" name="option" value="@opt.UserExamOptionViewModel.IsSelected">

【讨论】:

  • 我明白它现在如何更好地工作了。谢谢你。我很欣赏示例代码。我已经更新了我的问题。我取得了进展,但我仍然对获得所选选项感到困惑。这里有很多类似的帖子,但只有一部分在使用 Razor
  • 随着代码的进步,您无法不断更新您的问题......您的更新使现有答案变得无关紧要。您需要提出一个新问题。
猜你喜欢
  • 1970-01-01
  • 2021-04-17
  • 2020-03-20
  • 2014-07-23
  • 2021-05-14
  • 2014-05-29
  • 1970-01-01
  • 2022-11-01
  • 1970-01-01
相关资源
最近更新 更多