ASP.NET Core Razor Pages中Post Action无法获取ViewModel的解决方法
问题修复方案
核心问题分析
Post方法接收的CreateBallotViewModel属性为空,主要由三个原因导致:
- 模型中
choice和tracking是字段而非属性,ASP.NET Core模型绑定只支持带getter/setter的属性; - 视图中表单控件的name属性不匹配模型字段,且缺少关键的
ElectionId隐藏字段; - 控制器中DbContext初始化方式错误,且未验证模型状态。
1. 修正模型定义
将choice和tracking改为自动属性(添加get/set访问器),模型绑定才能正确识别并赋值:
using System; using System.Collections.Generic; namespace electronicvotingfyp.Models { public class CreateBallotViewModel { public List<ElectionOption> options { get; set; } public Election elect { get; set; } // 改为属性,添加get/set访问器 public string choice { get; set; } public string tracking { get; set; } //vote encrypted //signed vote //keys } }
2. 修复Razor视图
调整表单控件的name、id属性,添加隐藏字段传递ElectionId:
@model CreateBallotViewModel <div class="row"> <div class="col-md-5 offset-md-1"> <h4 class="mb-3">@Model.elect.Question</h4> <div class="my-3"> @using (Html.BeginForm(actionName: "CreateBallot", controllerName: "Account", FormMethod.Post)) { <!-- 添加隐藏字段传递ElectionId,否则Post时elect为null --> @Html.HiddenFor(m => m.elect.ElectionId) @foreach (var opt in Model.options) { <div class="form-check"> <!-- 使用RadioButtonFor生成正确的name和id --> @Html.RadioButtonFor(m => m.choice, opt.OptionName, new { @class = "form-check-input", id = $"choice_{opt.OptionName}" }) <!-- label的for属性对应单选按钮的id --> <label class="form-check-label" for="choice_@opt.OptionName">@opt.OptionName</label> </div> } <div class="form-check"> <!-- 修正name为"choice",使用asp-for自动匹配模型属性 --> <input asp-for="choice" type="radio" class="form-check-input" value="" id="choice_neutral"> <label class="form-check-label" for="choice_neutral">Neutral</label> </div> <div class="col-md-3"> <label asp-for="tracking" class="form-label">Tracking Number</label> <!-- 使用asp-for自动生成正确的name和id --> <input type="text" class="form-control" asp-for="tracking" placeholder="" required> <div class="invalid-feedback"> Security code required </div> </div> <hr class="my-4"> <button class="btn btn-primary" type="submit">Cast Ballot</button> } </div> </div> </div>
关键调整点:
- 移除所有
name="credit"的错误设置,用asp-for或RadioButtonFor自动生成与模型匹配的name属性; - 确保label的
for属性与对应单选按钮的id一致,提升交互体验; - 添加
@Html.HiddenFor(m => m.elect.ElectionId)传递选举ID,避免Post时cbm.elect为null。
3. 优化控制器代码
使用依赖注入获取DbContext,添加模型状态验证:
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using electronicvotingfyp.Models; using System.Security.Cryptography; using Org.BouncyCastle.OpenSsl; using Org.BouncyCastle.Crypto; using System.Text; public class AccountController : Controller { private readonly electronicvotingfypIdentityDbContext _dbContext; // 依赖注入DbContext,替代手动创建 public AccountController(electronicvotingfypIdentityDbContext dbContext) { _dbContext = dbContext; } [Authorize] [HttpGet] public IActionResult CreateBallot(int ElectionId) { var election = _dbContext.Elections.Single(u => u.ElectionId == ElectionId); var electionOptions = _dbContext.Options.Where(p => p.Election == election).ToList(); var cbm = new CreateBallotViewModel() { options = electionOptions, elect = election }; return View(cbm); } [Authorize] [HttpPost] public IActionResult CreateBallot(CreateBallotViewModel cbm) { // 先验证模型状态,排查绑定错误 if (!ModelState.IsValid) { // 重新加载选项和选举信息,返回视图显示错误 cbm.elect = _dbContext.Elections.Single(u => u.ElectionId == cbm.elect.ElectionId); cbm.options = _dbContext.Options.Where(p => p.Election == cbm.elect).ToList(); return View(cbm); } try { var keys = _dbContext.ElectionKeys.Single(u => u.RelatedElection.ElectionId == cbm.elect.ElectionId); PemReader pr = new PemReader(new StringReader(keys.publicKey)); AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair)pr.ReadObject(); ElectionKeySystemContrroller ks = new ElectionKeySystemContrroller(keyPair); byte[] inputChoice = Encoding.UTF8.GetBytes(cbm.choice); byte[] encryptedChoice = ks.Encrypt(inputChoice, 0, inputChoice.Length); // 后续逻辑:保存加密后的投票等 return View(cbm); } catch (Exception ex) { ModelState.AddModelError(string.Empty, "处理投票时发生错误:" + ex.Message); // 重新加载数据返回视图 cbm.elect = _dbContext.Elections.Single(u => u.ElectionId == cbm.elect.ElectionId); cbm.options = _dbContext.Options.Where(p => p.Election == cbm.elect).ToList(); return View(cbm); } } }
关键优化:
- 通过依赖注入获取
electronicvotingfypIdentityDbContext,避免手动创建时的配置缺失; - 添加
ModelState.IsValid验证,快速排查绑定错误; - 异常处理中重新加载模型数据,确保返回视图时页面内容完整。
内容的提问来源于stack exchange,提问作者Agossou Sara
相关产品推荐
相关产品推荐

