MVC Проверка на стороне сервера RadioButton и DropDownList - PullRequest
0 голосов
/ 16 мая 2019

Используя ASP.NET Core 2.2 Razor Pages, я изучаю привязку переключателей и выпадающих списков к модели страницы.

Многие люди спрашивают о проверке на стороне клиента, чтобы "заставить его работать".

Мой вопрос: когда я смотрю на этот код.Есть ли какая-либо проверка на стороне сервера, выполняемая механизмом привязки?

@foreach (var gender in Model.Genders)
{
    <input type="radio" asp-for="Gender" value="@gender" id="Gender@(gender)" /> @gender
}

@Html.DropDownListFor(x => x.Country, new List<SelectListItem>
{
    new SelectListItem() {Text = "Canada", Value="CA"},
    new SelectListItem() {Text = "USA", Value="US"},
    new SelectListItem() {Text = "Mexico", Value="MX"}
})  

Что мешает кому-либо публиковать пол "bababa" и страну "xxx", что может привести к неопределенному поведению в моем коде и базе данных?

Я был бы удивлен, если приведенный выше код выполняет такую ​​проверку (поправьте меня, если я ошибаюсь), и я не смог найти посты, спрашивающие об этом, потому что все спрашивают о проверке на стороне клиента.

Какой рекомендуемый подход здесь?

Ответы [ 2 ]

0 голосов
/ 17 мая 2019

Придумал собственное элегантное решение, так как я ничего не нашел там.

С помощью вспомогательного класса ниже, я объявлю свою модель с этим

[BindProperty]
public InputList Gender { get; set; } = new InputList(new[] { "Man", "Woman" });

[BindProperty]
public InputList Country { get; set; } = new InputList(new NameValueCollection()
{
    { "", "--Select--" },
    { "CA", "Canada" },
    { "US", "USA" },
    { "MX", "Mexico" }
});

Вставить переключатели и выпадающий список на моей странице

@foreach (var item in Model.Gender.ListItems)
{
    <input type="radio" asp-for="Gender.Value" value="@item.Value" id="Gender@(item.Value)" /><label for="Gender@(item.Value)" style="padding-right:15px;"> @item.Text </label>
}
<span asp-validation-for="Gender" class="text-danger"></span>

@Html.DropDownListFor(x => x.Country.Value, Model.Country.ListItems)
<span asp-validation-for="Country" class="text-danger"></span>

И вуаля! Валидация работает как на стороне клиента, так и на стороне сервера, обеспечивая правильность объявленного значения.

Конечно, можно перевести «Мужчина» и «Женщина» в константы, и можно переместить список стран в отдельный класс, который генерирует его один раз для всего приложения.

Вот вспомогательный класс InputList.

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace EmergenceGuardian.WebsiteTools.Web
{
    /// <summary>
    /// Represents a list of items to display as radio buttons or drop down list that can be bound to a web page and validated.
    /// </summary>
    [InputListValidation]
    public class InputList
    {
        /// <summary>
        /// Initializes a new instance of InputList with specified list of items that will be used for both the value and text.
        /// </summary>
        /// <param name="values">A list of string values reprenting valid values.</param>
        /// <param name="required">Whether this field is required.</param>
        public InputList(IEnumerable<string> values, bool required = true)
        {
            Required = required;
            foreach (var item in values)
            {
                ListItems.Add(new SelectListItem(item, item));
            }
        }

        /// <summary>
        /// Initializes a new instance of InputList with specified list of SelectListItem objects.
        /// </summary>
        /// <param name="values">A list of SelectListItem objects representing display text and valid values.</param>
        /// <param name="required">Whether this field is required.</param>
        public InputList(IEnumerable<SelectListItem> values, bool required = true)
        {
            Required = required;
            ListItems.AddRange(values);
        }

        /// <summary>
        /// Initializes a new instance of InputList with a NameValueCollection allowing quick collection initializer.
        /// </summary>
        /// <param name="values">The NameValueCollection containing display texts and valid values.</param>
        /// <param name="required">Whether this field is required.</param>
        public InputList(NameValueCollection values, bool required = true)
        {
            Required = required;
            foreach (var key in values.AllKeys)
            {
                ListItems.Add(new SelectListItem(values[key], key));
            }
        }

        /// <summary>
        /// Gets or sets whether this field is required.
        /// </summary>
        public bool Required { get; set; }
        /// <summary>
        /// Gets or sets the list of display text and valid values, used for display and validation.
        /// </summary>
        public List<SelectListItem> ListItems { get; set; } = new List<SelectListItem>();
        /// <summary>
        /// Gets or sets the user input value. This value can be bound to the UI and validated by InputListValidation.
        /// </summary>
        public string Value { get; set; }
    }

    /// <summary>
    /// Validates an InputList class to ensure Value is contained in ListItems.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    sealed public class InputListValidationAttribute : ValidationAttribute
    {
        private const string DefaultErrorMessage = "Selected value is invalid.";
        private const string DefaultRequiredErrorMessage = "The {0} field is required.";

        public InputListValidationAttribute()
        {
        }

        /// <summary>
        /// Validates whether InputList.Value contains a valid value.
        /// </summary>
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var input = value as InputList;
            if (input != null)
            {
                if (string.IsNullOrEmpty(input.Value))
                {
                    if (input.Required)
                    {
                        return new ValidationResult(string.Format(ErrorMessage ?? DefaultRequiredErrorMessage, validationContext.MemberName));
                    }
                }
                else if (input.ListItems?.Any(x => x.Value == input.Value) == false)
                {
                    return new ValidationResult(ErrorMessage ?? DefaultErrorMessage);
                }

            }
            return ValidationResult.Success;
        }
    }
}
0 голосов
/ 16 мая 2019

Проверка на стороне сервера и на стороне клиента важна, вам всегда нужно внедрять проверки на стороне сервера, возможно, проверки вашего клиента могут быть пропущены, но никогда проверки на стороне сервера, код, который вы опубликовали, не выполняют никакой проверки на стороне сервера

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...