ASP.NET Core如何禁用模型验证(或者从模型状态中移除某些属性)?

asp,net,core · 浏览次数 : 0

小编点评

**问题:** 在 ASP.NET Core 中,如何禁用某些请求的模型验证,只验证其他模型属性呢? **解决方案:** 1. 在页面模型中定义一个模型属性,并将其设置为 `Required` 属性。 2. 在页面视图中,将该属性值设置为 `false`。 3. 在模型绑定器中,使用 `[IgnoreProperty]` 注解忽略该属性的模型绑定。 4. 在模型验证器中,根据需要手动设置模型状态。 **示例代码:** ```csharp // Model public class UserNewModel : BaseAdminModel { [Required] [Display(Name = "用户名")] [StringLength(20)] public string UserName { get; set; } [Required(ErrorMessage = "用户密码不能为空!", AllowEmptyStrings = true)] [Display(Name = "密码")] [MaxLength(9, ErrorMessage = "密码最大为 9 个字符!")] [MinLength(3, ErrorMessage = "密码最小为 3 个字符!")] [DataType(DataType.Password)] [RegularExpression(@"^(?:[0-9]+[a-zA-Z]|[a-zA-Z]+[0-9])[a-zA-Z0-9]*$\", ErrorMessage = "密码至少包含一个字母和数字!")] public string Password { get; set; } } // View @model UserNewModel // Model binder protected override void OnPostFilePhoto_FileSelected(IFormFile filePhoto, IFormCollection values) { if (filePhoto != null) { string fileName = filePhoto.FileName; // ... } } ``` **注意:** * 在移除属性之前,请确保模型验证器已正确设置。 * 可以根据需要扩展此方法,例如设置默认值或自定义错误提示。

正文

 

这是一篇4年前的文章:【经验分享】在ASP.NET Core中,如果禁用某个请求的模型验证?

事隔多年,又有网友问到这个问题。我就来重新整理一下,顺便扩展一下之前的解决办法。

 

=====

这是一个来自网友【David】的提问。在 AppBoxCore 项目的新增用户页面,新增一个上传按钮:

<f:FileUpload ID="filePhoto" ShowRedStar="false" ShowEmptyLabel="true" ButtonText="上传个人头像" 
ButtonOnly="true" Required="false" ButtonIcon="ImageAdd" 
OnFileSelected="@Url.Handler("filePhoto_FileSelected")" 
OnFileSelectedFields="filePhoto">
</f:FileUpload>

  

后台代码:

public IActionResult OnPostFilePhoto_FileSelected(IFormFile filePhoto, IFormCollection values)
{
	if (filePhoto != null)
	{
		string fileName = filePhoto.FileName;

		// 。。。
	}

	return UIHelper.Result();
}

  

此时上传照片时,会弹出错误提示框(截图所示)。

The 用户名 field is required.
The 邮箱 field is required.
The 性别 field is required.
The 密码 field is required.

 

这是因为页面模型中定义了一个绑定属性:

[CheckPower(Name = "CoreUserNew")]
public class UserNewModel : BaseAdminModel
{
	[BindProperty]
	public User CurrentUser { get; set; }

	// ...
}

  

而在 POST 请求中会触发模型绑定,如果发现模型不完整就会报错。这个错误提示框是由 FineUICore 框架处理的,无需自己写代码。

现在问题就来了!

====================
对于上述场景,仅仅是上传图片而无需验证 CurrentUser 模型属性,该如何处理呢?

其实也很简单,只需要在处理器中清空模型状态就可:

public IActionResult OnPostFilePhoto_FileSelected(IFormFile filePhoto, IFormCollection values)
{
	ModelState.Clear();

	if (filePhoto != null)
	{
		string fileName = filePhoto.FileName;

		// 。。。
	}

	return UIHelper.Result();
}

  

 

Done!

====================
这个问题也确实让我走了不少弯路,刚开始总想着如何禁用某些POST请求的模型验证,想着微软总能为处理器(Handler)提供一些注解(Annotation)来吧,结果查了一圈没有发现!

后来,想着换个思路:既然找不到禁用的方法,就清空模型状态,结果也是一样的。

 

 

 

延伸思考
============================
上面既然可以使用ModelState.Clear();清空所有的模型状态,那是否也可以移除模型状态中的某些属性呢?

以用户登录表单为例(用户名+密码),先看下模型定义:

namespace FineUICore.Examples.WebForms.Pages.DataModel.Models
{
    public class User
    {
        [Required]
        [Display(Name = "用户名")]
        [StringLength(20)]
        public string UserName { get; set; }

        [Required(ErrorMessage = "用户密码不能为空!", AllowEmptyStrings = true)]
        [Display(Name = "密码")]
        [MaxLength(9, ErrorMessage = "密码最大为 9 个字符!")]
        [MinLength(3, ErrorMessage = "密码最小为 3 个字符!")]
        [DataType(DataType.Password)]
        [RegularExpression("^(?:[0-9]+[a-zA-Z]|[a-zA-Z]+[0-9])[a-zA-Z0-9]*$", ErrorMessage = "密码至少包含一个字母和数字!")]
        public string Password { get; set; }

    }
}

  

 

页面模型中,定义一个名为 CurrentUser 的绑定属性:

[BindProperty]
public User CurrentUser { get; set; }

  

在页面视图中,将用户名和密码通过两个文本输入框渲染到页面中:

<f:Window Width="350" WindowPosition="GoldenSection" EnableClose="false" IsModal="false" Title="登录表单" ID="Window1">
    <Items>
        <f:SimpleForm ShowHeader="false" BodyPadding="10" ShowBorder="false" ID="SimpleForm1">
            <Items>
                <f:TextBox For="CurrentUser.UserName"></f:TextBox>
                @* <f:TextBox For="CurrentUser.Password"></f:TextBox> *@
            </Items>
        </f:SimpleForm>
    </Items>
    <Toolbars>
        <f:Toolbar Position="Bottom" ToolbarAlign="Right" ID="Toolbar1">
            <Items>
                <f:Button OnClick="btnLogin_Click" OnClickFields="SimpleForm1" ValidateTarget="Top" ValidateForms="SimpleForm1" Type="Submit" Text="登录" ID="btnLogin"></f:Button>
                <f:Button Type="Reset" Text="重置" ID="btnReset"></f:Button>
            </Items>
        </f:Toolbar>
    </Toolbars>
</f:Window>

  

注意,上述代码中我们注释掉了 CurrentUser.Password,以便在后台验证模型状态验证失败的情况。

此时提交表单,FineUICore会自动弹出模型验证失败的消息,如下图所示。

 

这个逻辑上是没有问题的,那个弹出框提示是FineUICore系统处理的(无需用户编码),看下事件处理函数:

public IActionResult OnPostBtnLogin_Click()
{
    if (ModelState.IsValid)
    {
        if (CurrentUser.UserName == "admin" && CurrentUser.Password == "admin888")
        {
            ShowNotify("成功登录!", MessageBoxIcon.Success);
        }
        else
        {
            ShowNotify(String.Format("用户名({0})或密码({1})错误!",
                CurrentUser.UserName,
                CurrentUser.Password), MessageBoxIcon.Error);
        }
    }

    return UIHelper.Result();
}

  

为了从模型验证状态中移除某些属性,我们可以直接这么写:

public IActionResult OnPostBtnLogin_Click()
{
    ModelState.Remove("CurrentUser.Password");

    if (ModelState.IsValid)
    {
    ...
    }

}

  

参考文章:https://stackoverflow.com/questions/16266988/exclude-fields-from-model-validation

上述文章指出,调用 ModelState.Remove() 方法虽然不够优雅,但是可以快速解决问题。更加优雅的做法是自定义一个单独的视图模型,示例代码:

public class PersonViewModel
{
    [Required]
    public String FirstName { get; set; }

    [Required]
    public String LastName { get; set; }
}

public class PersonWithEmailViewModel : PersonViewModel
{
    [Required]
    public String Email { get; set; }
}

  

与ASP.NET Core如何禁用模型验证(或者从模型状态中移除某些属性)?相似的内容:

ASP.NET Core如何禁用模型验证(或者从模型状态中移除某些属性)?

这是一篇4年前的文章:【经验分享】在ASP.NET Core中,如果禁用某个请求的模型验证? 事隔多年,又有网友问到这个问题。我就来重新整理一下,顺便扩展一下之前的解决办法。 这是一个来自网友【David】的提问。在 AppBoxCore 项目的新增用户页面,新增一个上传按钮:

.NET周报【1月第2期 2023-01-13】

国内文章 【ASP.NET Core】按用户等级授权 https://www.cnblogs.com/tcjiaan/p/17024363.html 本文介绍了ASP.NET Core如何按照用户等级进行授权。 在 C# 9 中使用 foreach 扩展 https://www.cnblogs.co

.NET周报 【3月第2期 2023-03-12】

国内文章 ASP.NET Core中如何限制响应发送速率(不是调用频率) https://www.cnblogs.com/coredx/p/17195492.html ASP.NET Core中有很多RateLimit组件,.NET 7甚至推出了官方版本。不过这些组件的主要目标是限制客户端访问服务的

【ASP.NET Core】MVC操作方法如何绑定Stream类型的参数

咱们都知道,MVC在输入/输出中都需要模型绑定。因为HTTP请求发送的都是文本,为了使其能变成各种.NET 类型,于是在填充参数值之前需 ModelBinder 的参与,以将文本转换为 .NET 类型。 尽管 ASP.NET Core 已内置基础类型和复杂类型的各种 Binder,但有些数据还是不能

Visual Studio Code调试和发布ASP.NET Core Web应用

前言 上一篇文章主要讲了Visual Studio Code安装C#开发工具包并编写ASP.NET Core Web应用有兴趣的同学可以去看看,今天咱们主要是要讲讲如何在VS Code中调试和发布ASP.NET Core Web应用。 Visual Studio Code安装C#开发工具包并编写AS

如何将 Autofac 整合进 Net6.0 Core MVC 项目中

一、前言 1、简而言之 Asp.Net Core Mvc,我也用了很长一段时间了,它现在的编程模型和方式还是特别棒的,都是组件开发,什么都可以替换,当然了,您别抬杠,有些还是不能替换的。自从我们进入了跨平台开发的时代,IOC容器也成了一个不可或缺的东西了。微软为我们提供了一个默认实现,那就是 ISe

如何在现有项目中使用`Masa MiniApi`?

首先我们现有创建一个空的WebApi的项目模板,这个项目模板和MasaFramework本身没有任何关联,我们本博客只是使用的MasaFramework的MiniApi的包 创建Asp.NET Core 空的项目模板 项目名称MFMiniApi 其他信息看图,取消Https配置,也可以选择, 这就是

ASP.NET Core的全局拦截器(在页面回发时,如果判断当前请求不合法,不执行OnPost处理器)

ASP.NET Core RazorPages中,我们可以在页面模型基类中重载OnPageHandlerExecuting方法。 下面的例子中,BaseModel继承自 PageModel,是所有页面模型的基类。 推荐方案:在BaseModel.cs中,重载OnPageHandlerExecutin

【ASP.NET Core】标记帮助器——元素筛选

前一篇中老周从标记帮助的底层介绍关键性的接口,如 ITagHelper ,它是一个标志,用于识别哪些类属于 Tag Helper。 标记帮助器毕竟是针对 HTML 标记的,所以得筛选。说白了就是我写的这个帮助器在哪些 HTML 标记上起作用。这就需要拿出一个特性类。 [AttributeUsage(

Asp .Net Core 系列:详解鉴权(身份验证)以及实现 Cookie、JWT、自定义三种鉴权 (含源码解析)

什么是鉴权(身份验证)? https://learn.microsoft.com/zh-cn/aspnet/core/security/authentication/?view=aspnetcore-8.0 定义 鉴权,又称身份验证,是确定用户身份的过程。它验证用户提供的凭据(如用户名和密码)是否有