这个问题可能能弱智,但是困扰了我好长时间,网上也一直搜不到,今天偶然一个机会在外国的论坛上看见这个。
首先,我想要实现的是自动绑定下拉选项,网上搜到很多方法,但是大家都是用的ViewBag(ViewData)将实例化好的DropDownList放在里面然后传递到前台,我一开始也是这么做的,但是后来莫名其妙的就出错了,说是没有实例化对象。
后来我有看了一些官方文档,其中在ASP.NET Core 表单中的标记帮助程序“https://docs.microsoft.com/zh-cn/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-2.1#the-select-tag-helper”一章中,官方文档给出了正确的绑定方式,先摘要如下:
Select Tag Helper
asp-for
为 select 元素指定模型属性名称,asp-items
指定 option 元素。 例如:
<select asp-for="Country" asp-items="Model.Countries"></select>
示例:
using Microsoft.AspNetCore.Mvc.Rendering;
using System.Collections.Generic;
namespace FormsTagHelper.ViewModels
{
public class CountryViewModel { public string Country { get; set; } public List<SelectListItem> Countries { get; } = new List<SelectListItem> { new SelectListItem { Value = "MX", Text = "Mexico" }, new SelectListItem { Value = "CA", Text = "Canada" }, new SelectListItem { Value = "US", Text = "USA" }, }; } }
Index
方法初始化 CountryViewModel
,设置选定的国家/地区并将其传递到 Index
视图。
public IActionResult IndexOption(int id) { var model = new CountryViewModel(); model.Country = "CA"; return View(model); }
HTTP POST Index
方法显示选定内容:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index(CountryViewModel model) { if (ModelState.IsValid) { var msg = model.Country + " selected"; return RedirectToAction("IndexSuccess", new { message = msg}); } // If we got this far, something failed; redisplay form. return View(model); }
Index
视图:
@model CountryViewModel <form asp-controller="Home" asp-action="Index" method="post"> <select asp-for="Country" asp-items="Model.Countries"></select> <br /><button type="submit">Register</button> </form>
生成以下 HTML(选择“CA”时):
<form method="post" action="/"> <select id="Country" name="Country"> <option value="MX">Mexico</option> <option selected="selected" value="CA">Canada</option> <option value="US">USA</option> </select> <br /><button type="submit">Register</button> <input name="__RequestVerificationToken" type="hidden" value="<removed for brevity>" /> </form>
其中特别备注了
不建议将 ViewBag
或 ViewData
与选择标记帮助程序配合使用。 视图模型在提供 MVC 元数据方面更可靠且通常更不容易出现问题。
我才发现,其实正确的做法还是用模型还传递数据,我立马照做了,但是在提交的时候又出现了新的问题,
InvalidOperationException: The entity type 'SelectListGroup' requires a primary key to be defined.
后来百度后,在一个国外的网站上看到,说需要在模型属性中加上【NotMapped】这个Attribute,官方解释为:Denotes that a property or class should be excluded from database mapping.
如下:
[NotMapped]
public List<SelectListItem> Countis { get; set; } = new List<SelectListItem>();
试验后,果然就不出错了,我理解其实出错的原因在于,没有加这个Attribute,它还想要通过Primary Key 往数据库里面插入Contis的选择后数据,加上了之后,就没有这个对应操作了。
回到标题,我一直想找一个Attribute,来描述一个字段,这个字段是我需要在Views中显示,但是又不需要保存在数据库中的,最典型的例子就是在注册用户时候的“确认密码”文本框,你需要它在Views中让用户来输入,但是你肯定不会保存一次密码又保存一次“确认密码“,我一直没找到对应的方法,在解决上面的问题后,我果断的将【NotMapped】这个Attribute加到了我的确认密码属性上面,果然,重新生成的数据库中没有了确认密码字段。太棒了
[Display(Name = "确认密码")]
[Required(ErrorMessage = "您需要填写{0}")]
[StringLength(50, ErrorMessage = "{0}长度应在{2}至{1}个字符之间", MinimumLength = 6)]
[Compare("Password",ErrorMessage ="{0}应和{1}一致")]
[DataType(DataType.Password)]
[NotMapped]
public string ConfirmPassword { get; set; }