ASP.NET Core如何禁用模型驗證(或者從模型狀態中移除某些屬性)? 【經驗分享】在ASP.NET Core中,如果禁用某個請求的模型驗證?

 

這是一篇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; }
}

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章