c# - RadioButton 和 DropDownList 的 MVC 服务器端验证
问题描述
使用 ASP.NET Core 2.2 Razor 页面,我正在探索将单选按钮和下拉列表绑定到页面模型。
很多人都在询问客户端验证以“让它工作”。
我的问题是:当我查看这段代码时。绑定引擎是否正在执行任何服务器端检查?
@foreach (var gender in Model.Genders)
{
<input type="radio" asp-for="Gender" value="@gender" id="Gender@(gender)" /> @gender
}
@Html.DropDownListFor(x => x.Country, new List<SelectListItem>
{
new SelectListItem() {Text = "Canada", Value="CA"},
new SelectListItem() {Text = "USA", Value="US"},
new SelectListItem() {Text = "Mexico", Value="MX"}
})
是什么阻止某人发布性别“bababa”和国家/地区“xxx”,这可能会导致我的代码和数据库中出现未定义的行为?
如果上面的代码正在做这样的验证,我会感到惊讶(如果我错了,请纠正我),而且我找不到关于这个的帖子,因为每个人都在询问客户端验证。
这里推荐的方法是什么?
解决方案
想出了我自己优雅的解决方案,因为我什么都没发现。
使用下面的辅助类,我将用这个声明我的模型
[BindProperty]
public InputList Gender { get; set; } = new InputList(new[] { "Man", "Woman" });
[BindProperty]
public InputList Country { get; set; } = new InputList(new NameValueCollection()
{
{ "", "--Select--" },
{ "CA", "Canada" },
{ "US", "USA" },
{ "MX", "Mexico" }
});
在我的页面上插入单选按钮和下拉列表
@foreach (var item in Model.Gender.ListItems)
{
<input type="radio" asp-for="Gender.Value" value="@item.Value" id="Gender@(item.Value)" /><label for="Gender@(item.Value)" style="padding-right:15px;"> @item.Text </label>
}
<span asp-validation-for="Gender" class="text-danger"></span>
@Html.DropDownListFor(x => x.Country.Value, Model.Country.ListItems)
<span asp-validation-for="Country" class="text-danger"></span>
瞧!验证在客户端和服务器端都有效,确保发布的值是有效的。
当然,可以将“Man”和“Woman”移动到常量中,并且可以将国家列表移动到一个单独的类中,为整个应用程序生成一次。
这是 InputList 帮助器类。
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace EmergenceGuardian.WebsiteTools.Web
{
/// <summary>
/// Represents a list of items to display as radio buttons or drop down list that can be bound to a web page and validated.
/// </summary>
[InputListValidation]
public class InputList
{
/// <summary>
/// Initializes a new instance of InputList with specified list of items that will be used for both the value and text.
/// </summary>
/// <param name="values">A list of string values reprenting valid values.</param>
/// <param name="required">Whether this field is required.</param>
public InputList(IEnumerable<string> values, bool required = true)
{
Required = required;
foreach (var item in values)
{
ListItems.Add(new SelectListItem(item, item));
}
}
/// <summary>
/// Initializes a new instance of InputList with specified list of SelectListItem objects.
/// </summary>
/// <param name="values">A list of SelectListItem objects representing display text and valid values.</param>
/// <param name="required">Whether this field is required.</param>
public InputList(IEnumerable<SelectListItem> values, bool required = true)
{
Required = required;
ListItems.AddRange(values);
}
/// <summary>
/// Initializes a new instance of InputList with a NameValueCollection allowing quick collection initializer.
/// </summary>
/// <param name="values">The NameValueCollection containing display texts and valid values.</param>
/// <param name="required">Whether this field is required.</param>
public InputList(NameValueCollection values, bool required = true)
{
Required = required;
foreach (var key in values.AllKeys)
{
ListItems.Add(new SelectListItem(values[key], key));
}
}
/// <summary>
/// Gets or sets whether this field is required.
/// </summary>
public bool Required { get; set; }
/// <summary>
/// Gets or sets the list of display text and valid values, used for display and validation.
/// </summary>
public List<SelectListItem> ListItems { get; set; } = new List<SelectListItem>();
/// <summary>
/// Gets or sets the user input value. This value can be bound to the UI and validated by InputListValidation.
/// </summary>
public string Value { get; set; }
}
/// <summary>
/// Validates an InputList class to ensure Value is contained in ListItems.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
sealed public class InputListValidationAttribute : ValidationAttribute
{
private const string DefaultErrorMessage = "Selected value is invalid.";
private const string DefaultRequiredErrorMessage = "The {0} field is required.";
public InputListValidationAttribute()
{
}
/// <summary>
/// Validates whether InputList.Value contains a valid value.
/// </summary>
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var input = value as InputList;
if (input != null)
{
if (string.IsNullOrEmpty(input.Value))
{
if (input.Required)
{
return new ValidationResult(string.Format(ErrorMessage ?? DefaultRequiredErrorMessage, validationContext.MemberName));
}
}
else if (input.ListItems?.Any(x => x.Value == input.Value) == false)
{
return new ValidationResult(ErrorMessage ?? DefaultErrorMessage);
}
}
return ValidationResult.Success;
}
}
}
推荐阅读
- c# - html pop up form always returns the first value
- python - 如何将 `app_settings` 的 `AuthenticationMethod` 设置为 `username_email`?
- python - Windows上的芹菜结果后端
- ffmpeg - Libav:无法从 d.tube 读取带有 mp4 文件的帧
- android - AlarmManager 是否将设备从打盹模式唤醒
- javascript - jQuery-UI 对话框仅显示 for 循环的最后一次迭代
- javascript - 如果正则表达式字符串存储在单独的 javascript 文件中,则正则表达式不起作用
- asp.net-core - 具有队列处理功能的 .NET 核心 Web api
- javascript - 使用 NPM 下载包文档
- angular - Angular 6 - 如何告诉 Angular 使用自定义属性的数据前缀而不是将它们直接放在 DOM 元素上?