.net core .net core 2.1验证状态:无效

.net core .net core 2.1验证状态:无效,.net-core,asp.net-core-mvc,.net Core,Asp.net Core Mvc,当我提交创建时,以下简单的.NET Core 2.1 MVC代码报告“验证状态:无效”。没有业主财产,一切正常;如果不需要所有者的财产,它就可以工作 所有者是服务器端上下文中的当前用户,不应从客户端提交,因此Create.cshtml表单中没有所有者输入 错误: info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1] Executing action method AnnouncementApp.Contr

当我提交创建时,以下简单的.NET Core 2.1 MVC代码报告“验证状态:无效”。没有业主财产,一切正常;如果不需要所有者的财产,它就可以工作

所有者是服务器端上下文中的当前用户,不应从客户端提交,因此Create.cshtml表单中没有所有者输入

错误:

info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
      Executing action method AnnouncementApp.Controllers.AnnouncementsController.Create (AnnouncementApp) with arguments (AnnouncementApp.Models.Announcement) - Validation state: Invalid
模型:

using System;
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using AnnouncementApp.Models.Attributes;
using Microsoft.AspNetCore.Identity;
//using System.Security.Claims;

namespace AnnouncementApp.Models
{
    public class Announcement
    {   
        public int ID { get; set; }
        [Required]
        public string Content { get; set; }
        [Display(Name = "Start Date and Time")]
        public DateTime StartDate { get; set; }

        [StartEndDate("End Date and Time must be after Start Date and Time")]
        [Display(Name = "End Date and Time")]
        public DateTime EndDate { get; set; }

        [Required]
        [BindNever]
        public IdentityUser Owner { get; set; }
    }   
}
控制器方法:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create([Bind("ID,Content,StartDate,EndDate")] Announcement announcement)
    {
        if (ModelState.IsValid)
        {
            var user = await _userManager.GetUserAsync(this.User);
            announcement.Owner = user;
            _context.Add(announcement);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        return View(announcement);
    }
[HttpPost]
[ValidateAntiForgeryToken]
公共异步任务创建([Bind(“ID,Content,StartDate,EndDate”)]公告)
{
if(ModelState.IsValid)
{
var user=await\u userManager.GetUserAsync(this.user);
公告。所有者=用户;
_添加(公告);
wait_context.SaveChangesAsync();
返回重定向到操作(名称(索引));
}
返回视图(公告);
}
Create.cshtml

@model AnnouncementApp.Models.Announcement

@{
    ViewData["Title"] = "Create";
}

<h2>Create</h2>

<h4>Announcement</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Content" class="control-label"></label>
                <textarea asp-for="Content" class="form-control"></textarea>
                <span asp-validation-for="Content" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="StartDate" class="control-label"></label>
                <input asp-for="StartDate" class="form-control" />
                <span asp-validation-for="StartDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="EndDate" class="control-label"></label>
                <input asp-for="EndDate" class="form-control" />
                <span asp-validation-for="EndDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
@model AnnouncementApp.Models.Announcement
@{
ViewData[“标题”]=“创建”;
}
创造
公告

返回列表 @节脚本{ @{wait Html.RenderPartialAsync(“_validationScript”);} }
我不能100%确定问题的定义,但是如果您想消除“Model Invalid”错误,因为您总是通过HttpContext设置Owner属性,您可以在验证模型之前使用以下方法:

ModelState["Owner"].ValidationState = ModelValidationState.Valid
我认为您的问题是您告诉路由器永远不要绑定“Owner”,但您仍然告诉它是必需的,因此ModelState可能会使它无效

只要使用了“Required”注释,我认为如果没有正确设置,ModelState就不会生效

例如:

ModelState["Owner"].ValidationState = ModelValidationState.Valid
if (ModelState.IsValid)
        {
            var user = await _userManager.GetUserAsync(this.User);
            announcement.Owner = user;
            _context.Add(announcement);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        return View(announcement);

对于
公告
,它将对客户端验证和数据库表应用
[必需]

如注释所示,您可以考虑拆分<代码>公告>代码>到DB模型和VIEW模型,您可以为客户验证定义一个新的<>代码>通知/查看模型> />代码。p> 对于另一个选项,您可以尝试在fluent api中配置

[Required]
,而不是属性

下面是详细的步骤

  • 更改
    公告

    public class Announcement
    {
    public int ID { get; set; }
    [Required]
    public string Content { get; set; }
    [Display(Name = "Start Date and Time")]
    public DateTime StartDate { get; set; }
    public string OwnerId { get; set; }
    //[Required]
    [BindNever]
    [ForeignKey("OwnerId")]
    public IdentityUser Owner { get; set; }
    }
    
        protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
    
        builder.Entity<Announcement>()
               .Property(a => a.OwnerId)
               .IsRequired();           
    }
    
  • ApplicationDbContext

    public class Announcement
    {
    public int ID { get; set; }
    [Required]
    public string Content { get; set; }
    [Display(Name = "Start Date and Time")]
    public DateTime StartDate { get; set; }
    public string OwnerId { get; set; }
    //[Required]
    [BindNever]
    [ForeignKey("OwnerId")]
    public IdentityUser Owner { get; set; }
    }
    
        protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
    
        builder.Entity<Announcement>()
               .Property(a => a.OwnerId)
               .IsRequired();           
    }
    
    模型创建时受保护的覆盖无效(ModelBuilder)
    {
    基于模型创建(生成器);
    builder.Entity()
    .Property(a=>a.OwnerId)
    .IsRequired();
    }
    
  • 控制器

        [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create([Bind("ID,Content,StartDate")] Announcement announcement)
    {
        if (ModelState.IsValid)
        {
            var user = await _userManager.GetUserAsync(User);
            announcement.Owner = user;
            _context.Add(announcement);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        return View(announcement);
    }
    
    [HttpPost]
    [ValidateAntiForgeryToken]
    公共异步任务创建([Bind(“ID,Content,StartDate”)]公告)
    {
    if(ModelState.IsValid)
    {
    var user=await\u userManager.GetUserAsync(用户);
    公告。所有者=用户;
    _添加(公告);
    wait_context.SaveChangesAsync();
    返回重定向到操作(名称(索引));
    }
    返回视图(公告);
    }
    

  • 你需要一个隐藏的ID字段吗?不,我不需要。我认为这是必要的,而不仅仅是冲突。似乎需要优先考虑。我希望将其设置为必需,因为我希望实体框架脚手架使结果OwnerId列上的创建表sql不为NULL;但是这破坏了模型绑定validation.int应该转换为NOTNULL。智力?(或可为NULL的数据类型)转换为NULL。但是,您可能需要考虑从域模型中创建一组视图模型。域模型可以与数据库关联,视图模型与网页关联。@sean是正确的。为什么要包含一些您永远不希望从客户端传递来作为客户端验证的内容?仅使用视图通过任何测试和输入验证所需的内容创建视图模型。@sean是正确的。我应该从域模型中分离ViewModel。谢谢。强制国家生效可能不是一个好的做法。我将从域模型中分离ViewModel Fluent API可能有些过分。ViewModel是一个干净的解决方案。