如何为有条件的必需属性实现客户端验证 - Razor ASP.NET 核心
Posted
技术标签:
【中文标题】如何为有条件的必需属性实现客户端验证 - Razor ASP.NET 核心【英文标题】:How to implement client side validation for a conditional required property - Razor ASP.NET core 【发布时间】:2021-10-22 02:40:20 【问题描述】:我有一个在两个页面之间共享的模型(安全日志、失物招领)。我希望仅当属性 'AppType' = "Security Log" 时才需要属性 'Narrative'。
我的服务器端验证工作正常,但是当我保存表单时,表单上的下拉值会丢失它们的值,因为我使用的是 ViewBag。这是我目前拥有的。
SecurityLog.cs
public string AppType get; set;
[RequiredIf(nameof(AppType), "Security Log", ErrorMessage = "Narrative is required")]
public string Narrative get; set;
public class RequiredIfAttribute : ValidationAttribute
public string PropertyName get; set;
public object Value get; set;
public RequiredIfAttribute(string propertyName, object value, string errorMessage = "")
PropertyName = propertyName;
ErrorMessage = errorMessage;
Value = value;
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
var instance = validationContext.ObjectInstance;
var type = instance.GetType();
var proprtyvalue = type.GetProperty(PropertyName).GetValue(instance, null);
if (proprtyvalue.ToString() == Value.ToString() && value == null)
return new ValidationResult(ErrorMessage);
return ValidationResult.Success;
有谁知道如何在我的安全日志创建页面上实现客户端验证(javascript/jquery/etc..)?我发现我的项目的其余必填字段验证客户端,因为下拉值被保留。当我填写了除 Narrative 之外的所有必填字段并单击保存时,我会丢失 dd 值,因此我知道这是在服务器端处理的。
点击保存前的创建页面示例
点击保存后创建页面示例
创建页面逻辑
<div class="form-group">
<label asp-for="SecurityLog.EntityID" class="control-label"></label>
<select id="entity" asp-for="SecurityLog.EntityID" class="form-control" asp-items="ViewBag.EntityID">
<option value="">--Select Entity--</option>
</select>
<span asp-validation-for="SecurityLog.EntityID" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="SecurityLog.LocationID" class="control-label"></label>
<select id="location" asp-for="SecurityLog.LocationID" class="form-control"
asp-items="ViewBag.LocationID">
<option value="">--Select Location--</option>
</select>
<span asp-validation-for="SecurityLog.LocationID" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="SecurityLog.ShiftRangeID" class="control-label"></label>
<select asp-for="SecurityLog.ShiftRangeID" class="form-control" asp-items="ViewBag.ShiftRangeID">
<option value="">--Select Shift--</option>
</select>
<span asp-validation-for="SecurityLog.ShiftRangeID" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="SecurityLog.EventStart" class="control-label"></label>
<input asp-for="SecurityLog.EventStart" class="form-control" id="datepicker2" type="text" autocomplete="off" />
<span asp-validation-for="SecurityLog.EventStart" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="SecurityLog.EventEnd" class="control-label"></label>
<input asp-for="SecurityLog.EventEnd" class="form-control" id="datepicker3" type="text" autocomplete="off" />
<span asp-validation-for="SecurityLog.EventEnd" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="SecurityLog.ContactName" class="control-label"></label>
<input asp-for="SecurityLog.ContactName" class="form-control" autocomplete="off" />
<span asp-validation-for="SecurityLog.ContactName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="SecurityLog.EventTypeID" class="control-label"></label>
<select id="selectEventType" asp-for="SecurityLog.EventTypeID" class="form-control" asp-items="ViewBag.EventTypeID">
<option value="">--Select Event Type--</option>
</select>
<span asp-validation-for="SecurityLog.EventTypeID" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="SecurityLog.Narrative" class="control-label"></label>
<textarea asp-for="SecurityLog.Narrative" class="form-control" style="height:200px;"></textarea>
<span asp-validation-for="SecurityLog.Narrative" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" id="btnCreateLog" onclick="return lockedOrNot()" />
</div>
创建.cshtml.cs
[BindProperty]
public SecurityLog SecurityLog get; set;
[BindProperty(SupportsGet = true)]
public int entity get; set;
SelectList FilteredLocation;
public JsonResult OnGetLocations()
FilteredLocation = new SelectList(_context.Location.Where(c => c.EntityID == entity).Where(c =>c.Active == "Y").OrderBy(c =>c.Name), "ID", "Name");
return new JsonResult(FilteredLocation);
public IActionResult OnGetAsync()
ViewData["EntityID"] = new SelectList(_context.Entity.Where(a => a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
ViewData["ShiftRangeID"] = new SelectList(_context.ShiftRange.Where(a=>a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
ViewData["LocationID"] = new SelectList(_context.Location.Where(a=>a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
ViewData["EventTypeID"] = new SelectList(_context.EventType.Where(a=>a.Active == "Y").OrderBy(a => a.Name), "ID","Name");
return Page();
public async Task<IActionResult> OnPostAsync()
if (!ModelState.IsValid)
ViewData["EntityID"] = new SelectList(_context.Entity.Where(a => a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
ViewData["ShiftRangeID"] = new SelectList(_context.ShiftRange.Where(a => a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
ViewData["LocationID"] = new SelectList(_context.Location.Where(a => a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");//Not workiong
ViewData["EventTypeID"] = new SelectList(_context.EventType.Where(a => a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
//return Page(SecurityLog); // Return also the entity //Errors out "No overload for message 'Page ' takes 1 argument
return Page();
_context.SecurityLog.Add(SecurityLog);
await _context.SaveChangesAsync();
Message = "Entry added successfully!";
//return RedirectToPage("Index");
return Page();
【问题讨论】:
只有当您填写除 Narrative 之外的所有必填字段并单击保存时,控制器上才会出现缺失值吗? @Chaodeng - 为了清晰起见,我在上面添加了屏幕截图和一些示例代码。点击保存后除了 Narrative 以外的所有字段都填写了缺失值,但这不是 MVC 项目。 我建议你使用像Vue和Vee-Validate这样的js框架。如果你有兴趣,我可以提供一个简单的例子。 @Max - 当然。我很感兴趣。我是否需要删除上面对 Narrative 的服务器端验证,并将 Narrative 属性保留为不需要? 可以为两张截图添加控制器代码吗?我认为您没有重新发送这两个组合列表。 【参考方案1】:验证失败时必须返回列表和实体。
public IActionResult OnGetAsync()
ViewData["EntityID"] = new SelectList(_context.Entity.Where(a => a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
ViewData["ShiftRangeID"] = new SelectList(_context.ShiftRange.Where(a=>a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
ViewData["LocationID"] = new SelectList(_context.Location.Where(a=>a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
ViewData["EventTypeID"] = new SelectList(_context.EventType.Where(a=>a.Active == "Y").OrderBy(a => a.Name), "ID","Name");
return Page();
public async Task<IActionResult> OnPostAsync()
if (!ModelState.IsValid)
// Where and When is invoked ? Is necessary for locations ?
// FilteredLocation = new SelectList(_context.Location.Where(c => c.EntityID == entity).Where(c =>c.Active == "Y").OrderBy(c =>c.Name), "ID", "Name");
// return new JsonResult(FilteredLocation);
// Return the ViewData
ViewData["EntityID"] = new SelectList(_context.Entity.Where(a => a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
ViewData["ShiftRangeID"] = new SelectList(_context.ShiftRange.Where(a=>a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
ViewData["LocationID"] = new SelectList(_context.Location.Where(a=>a.Active == "Y").OrderBy(a => a.Name), "ID", "Name");
ViewData["EventTypeID"] = new SelectList(_context.EventType.Where(a=>a.Active == "Y").OrderBy(a => a.Name), "ID","Name");
// Return also the entity
// Somewhere you have to set SecurityLog
return Page();
// From where came the SecurityLog ?
_context.SecurityLog.Add(SecurityLog);
await _context.SaveChangesAsync();
Message = "Entry added successfully!";
// If you return always the same page, you must return also here the ViewData or move from it the top
//return RedirectToPage("Index");
return Page();
【讨论】:
感谢您的帮助!我的值现在被保留用于除位置之外的所有字段。位置是从另一个下拉实体驱动的,我最初没有将其包含在我的代码中,但我已将逻辑添加到上面的代码中。我怎样才能保留位置值?此外,返回页面(安全日志)不起作用 b/c 方法“页面”没有重载需要 1 个参数。如果我只是返回 Page() 它似乎可以工作。 我不知道您如何在GET
上返回Securitylog
实体的代码,但您必须在OnPostAsync
上实现相同的代码以上是关于如何为有条件的必需属性实现客户端验证 - Razor ASP.NET 核心的主要内容,如果未能解决你的问题,请参考以下文章
如何为每个 url 配置 grails/spring 身份验证方案?
如何为Amazon EMR生成trustedCertificates.pem和certificateChain.pem文件?