簡體   English   中英

ASP.NET Core 3.0 形式 ModelState 始終無效

[英]ASP.NET Core 3.0 form ModelState always invalid

我正在將舊的 ASP.NET 4.5 網站移植到 ASP.NET Core 3.0 的過程中,並且在身份 Razor 頁面及其工作方式方面遇到了一些問題。

例如,在應用程序的注冊頁面,如下圖,表格是完整填寫的,但是當點擊按鈕時,我在Register.cs文件的PostAsync()方法中打斷點, Input為model綁定,一切總是null ,除了我在 HTML 中設置初始選擇值的枚舉。

注意:是的,我在代碼文件中看到了輸入。 那不是問題。 我在截屏后擺脫了它。

表格錯誤

    [BindProperty]
    public InputModel Input { get; set; }

    public class InputModel
    {
        [Required]
        [Display(Name = "First Name")]
        public string FirstName { get; set; }

        [Required]
        [Display(Name = "Last Name")]
        public string LastName { get; set; }

        [Required]
        [Display(Name = "Gender")]
        public Gender Gender { get; set; }

        [Required]
        [Phone]
        [Display(Name = "MobilePhone")]
        public string MobilePhone { get; set; }

        [Required]
        [EmailAddress]
        [Display(Name = "Email")]
        public string Email { get; set; }

        [Required]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

        [DataType(DataType.Password)]
        [Display(Name = "Confirm password")]
        [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
        public string ConfirmPassword { get; set; }
    }

在我的Startup文件中:

 services.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
            .ConfigureApiBehaviorOptions(options =>
            {
                options.SuppressConsumesConstraintForFormFileParameters = true;
                options.SuppressInferBindingSourcesForParameters = true;
                options.SuppressModelStateInvalidFilter = true;
                options.SuppressMapClientErrors = true;

            });

由於表單值始終為 null,為何ModelState始終無效?

這是形式的 HTML:

<form asp-route-returnUrl="@Model.ReturnUrl"
                      class="form-horizontal push-50-t push-50 form-register"
                      method="post">
                    <div asp-validation-summary="All" class="text-danger"></div>
                    <!-- form entry - first name -->
                    <div class="form-group">
                        <div class="col-xs-12">
                            <div class="form-material form-material-success">
                                <label asp-for="Input.FirstName"></label>
                                <input asp-for="Input.FirstName" type="text"
                                       id="register-firstname" name="register-firstname" 
                                       class="form-control" placeholder="Enter your first name" />
                                <span asp-validation-for="Input.FirstName" class="text-danger"></span>
                            </div>
                        </div>
                    </div>
                    <!-- form entry - last name -->
                    <div class="form-group">
                        <div class="col-xs-12">
                            <div class="form-material form-material-success">
                                <label asp-for="Input.LastName"></label>
                                <input asp-for="Input.LastName" type="text"
                                       id="register-lastname" name="register-lastname"
                                       class="form-control" placeholder="Enter your last name" />
                                <span asp-validation-for="Input.LastName" class="text-danger"></span>
                            </div>
                        </div>
                    </div>
                    <!-- form entry - gender -->
                    <div class="form-group">
                        <div class="col-xs-12">
                            <div class="form-material form-material-success">
                                <label asp-for="Input.Gender"></label>
                                <select class="form-control" asp-for="Input.Gender"  id="register-gender" name="register-gender"
                                        placeholder="Please enter Male/Female">
                                <option selected="selected" value="@Gender.Male">Male</option>
                                <option  value="@Gender.Female">Female</option>

                                </select>
                                <span asp-validation-for="Input.Gender" class="text-danger"></span>
                            </div>
                        </div>
                    </div>
                    <!-- form entry - mobile phone -->
                    <div class="form-group">
                        <div class="col-xs-12">
                            <div class="form-material form-material-success">
                                <label asp-for="Input.MobilePhone"></label>
                                <input asp-for="Input.MobilePhone" type="tel"
                                       id="register-mobilephone" name="register-mobilephone"
                                       class="form-control" placeholder="Provide your mobile phone number" />
                                <span asp-validation-for="Input.MobilePhone" class="text-danger"></span>
                            </div>
                        </div>
                    </div>
                    <!-- form entry - email -->
                    <div class="form-group">
                        <div class="col-xs-12">
                            <div class="form-material form-material-success">
                                <label asp-for="Input.Email"></label>
                                <input asp-for="Input.Email" 
                                       type="email" id="register-email" name="register-email"
                                       class="form-control" placeholder="Your email address" />
                                <span asp-validation-for="Input.Email" class="text-danger"></span>
                            </div>
                        </div>
                    </div>
                    <!-- form entry - password -->
                    <div class="form-group">
                        <div class="col-xs-12">
                            <div class="form-material form-material-success">
                                <label asp-for="Input.Password"></label>
                                <input asp-for="Input.Password" 
                                       type="password" id="register-password" name="register-password"
                                       class="form-control" placeholder="Choose a strong password" />
                                <span asp-validation-for="Input.Password" class="text-danger"></span>
                            </div>
                        </div>
                    </div>
                    <!-- form entry - confirm password -->
                    <div class="form-group">
                        <div class="col-xs-12">
                            <div class="form-material form-material-success">
                                <label asp-for="Input.ConfirmPassword"></label>
                                <input asp-for="Input.ConfirmPassword" 
                                       type="password" id="register-password2" name="register-password2"
                                       class="form-control" placeholder="Confirm your password" />
                                <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
                            </div>
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="col-xs-7 col-sm-8">
                            <label class="css-input switch switch-sm switch-success">
                                <input type="checkbox" id="register-terms" name="register-terms"><span></span> I agree with terms &amp; conditions
                            </label>
                        </div>
                        <div class="col-xs-5 col-sm-4">
                            <div class="font-s13 text-right push-5-t">
                                <a href="#" data-toggle="modal" data-target="#modal-terms">View Terms</a>
                            </div>
                        </div>
                    </div>
                    <div class="form-group">
                        <div class="col-xs-12 col-sm-6 col-sm-offset-3">
                            <button id="register-button" class="btn btn-sm btn-block btn-success" type="submit">Create Account</button>
                        </div>
                    </div>
                </form>
                <!-- END Register Form -->

更新:根據評論者的要求,這里也是請求有效負載。

在此處輸入圖像描述

經過幾個小時的反復試驗,簡單的答案是 html 標記中的 name 屬性必須是 model 屬性名稱。

我將其發布為答案,以便遇到此問題的任何其他人都可以在這里輕松找到解決方案。

即這是導致每個屬性失敗的原因

 <!-- form entry - email -->
   <div class="form-group">
      <div class="col-xs-12">
         <div class="form-material form-material-success">
            <label asp-for="Input.Email"></label>
            <input asp-for="Input.Email" type="email" id="register-email" **name="register-email"**
                class="form-control" placeholder="Your email address" />
           <span asp-validation-for="Input.Email" class="text-danger"></span>
        </div>
    </div>
 </div>

輸入標簽助手中的 asp-for 屬性助手是創建 id 和 name 屬性的東西,因此如果您使用帶有 asp-for 的標簽助手,您也不能放入自己的 name= 屬性。

正如您在回答中指出的那樣,這里的問題是由於您的代碼覆蓋了asp-for設置的name值。 而且,通常,您確實希望保留該默認值。

然而,值得指出的是,嚴格遵守該命名約定並不是絕對必要的。 如果您遇到需要,可以使用一些變體。

上下文不可知綁定

首先,綁定到復雜對象時的操作參數或 controller 屬性的名稱是可選的( 參考)。 因此,例如,您可以使用默認的Input.LastName (由asp-for生成),或者您可以簡單地使用LastName 這對於暴露特定 model 的標記但可能不知道用於不同操作的參數名稱的可重用組件(例如,視圖組件或部分視圖)很有用。 當然,這也可能為歧義創造空間,所以我認為最好的做法是明確的,除非有一個令人信服的業務需求來為參數名稱提供靈活性。

帶有[Bind(Prefix="")]的自定義前綴

其次,您可以通過在操作參數上使用[Bind(Prefix="MyInput")]更改綁定 model 前綴的名稱,或者在您的情況下[BindProperty(Name="MyInput")]參考)。 此時,您不妨更改參數或屬性名稱。 但是,當您的標記命名約定與 C# 中的首選參數名稱不匹配時,這可以提供一些靈活性。

使用IModelBinder自定義綁定

最后,您還可以創建一個自定義 model 綁定器,該綁定器派生自IModelBinder以開發自定義約定,如何將 map 表單名稱綁定到操作參數以及綁定model屬性。 如果您需要保持與舊客戶端或命名約定的兼容性,或者有其他原因更喜歡非標准命名約定,這將非常有用。 自定義 model 綁定器通常很復雜,但為了支持基本約定,例如將snake-case轉換為PascalCase甚至snake-caseobject.Notation ,它們不需要太復雜。

結論

這有點落伍了。 對於大多數用戶和案例而言,就簡單性、可預測性和可維護性而言,使用由asp-for強制執行的開箱即用約定是最好的方法。 但請注意,這不是唯一的選擇,因為在許多情況下,您可能希望 HTML name屬性與預期的 ASP.NET 核心默認值不同。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM