ASP.NET Блейзор Требовал проверки с помощью InputSelect

#c# #asp.net #blazor #blazor-server-side

#c# #asp.net #blazor #blazor-на стороне сервера

Вопрос:

Я пытаюсь заставить требуемый атрибут работать с InputSelect, но проверка не работает на сервере Blazor. Форма может быть отправлена без выбора. Интересно, что это работает, когда свойство модели имеет значение null . До .NET 5.0 он не работал с обнуляемыми типами, потому что InputSelect их не поддерживал. Однако мне нужно свойство required, не требующее обнуления, потому что я хочу повторно использовать dto из моего API в качестве модели и потому, что это логически неверно.

введите описание изображения здесь

 public class SomeModel
{
    [Required]
    public string SomeString { get; set; }

    [Required]
    public SomeEnum SomeEnum { get; set; }

    [Required]
    public SomeEnum? SomeNullableEnum { get; set; }

    [Required]
    public int SomeInt { get; set; }

    [Required]
    public int? SomeNullableInt { get; set; }
}

public enum SomeEnum
{
    A = 1,
    B = 2
}
  

Страница

 @page "/testrequired"
@using TestNET5BlazorServerApp.Data;


<EditForm Model="Model" OnValidSubmit="Submit">

    <DataAnnotationsValidator />
    <ValidationSummary />

    String:
    <br />
    <InputText @bind-Value="Model.SomeString" />
    <br />
    <br />
    Enum:
    <br />
    <InputSelect @bind-Value="Model.SomeEnum">
        <option value="">Select Enum</option>
        <option value="@SomeEnum.A">@SomeEnum.A</option>
        <option value="@SomeEnum.B">@SomeEnum.B</option>
    </InputSelect>
    <br />
    <br />

    Nullable Enum:
    <br />
    <InputSelect @bind-Value="Model.SomeNullableEnum">
        <option>Select Nullable Enum</option>
        <option value="@SomeEnum.A">@SomeEnum.A</option>
        <option value="@SomeEnum.B">@SomeEnum.B</option>
    </InputSelect>
    <br />
    <br />

    Int:
    <br />
    <InputSelect @bind-Value="Model.SomeInt">
        <option>Select Int</option>
        <option value="1">1</option>
        <option value="2">2</option>
    </InputSelect>
    <br />
    <br />

    Nullable Int:
    <br />
    <InputSelect @bind-Value="Model.SomeNullableInt">
        <option>Select Nullable Int</option>
        <option value="1">1</option>
        <option value="2">2</option>
    </InputSelect>
    <br />
    <br />

    <button type="submit">Save</button>
</EditForm>

@code 
{
    SomeModel Model = new Data.SomeModel();

    void Submit()
    {
        System.Diagnostics.Debug.WriteLine("Enum "   Model.SomeEnum);
        System.Diagnostics.Debug.WriteLine("Nullable Enum "   Model.SomeNullableEnum);
        System.Diagnostics.Debug.WriteLine("Int "   Model.SomeInt);
        System.Diagnostics.Debug.WriteLine("Nullable Int "   Model.SomeNullableInt);
    }
}
  

Ответ №1:

Не уверен, что я вас понимаю, но давайте попробуем…

Однако я хочу, чтобы обязательное свойство не обнулялось

Имеете ли вы в виду, например, что вам нужно такое свойство, как следующее:

 [Required]
public int SomeInt { get; set; }
  

быть привязанным к компоненту InputSelect, подобному этому:

 <InputSelect @bind-Value="Model.SomeInt">
    <option>Select Int</option>
    <option value="1">1</option>
    <option value="2">2</option>
</InputSelect>
  

И когда пользователь нажимает кнопку «Отправить», должно отображаться сообщение о проверке, если пользователь не выбрал значение?

Если да, то это мой ответ:

Компонент InputSelect, по крайней мере, до .Net 5.0, может связываться только со строковыми и перечисляемыми типами.

Если вы хотите, чтобы ваш InputSelect поддерживал привязку к int, как в приведенном выше случае, вы должны подклассировать его следующим образом…

 public class InputSelectNumber<T> : InputSelect<T>
    {
        
        protected override bool TryParseValueFromString(string value, out T result, out string validationErrorMessage)
        {
            if (typeof(T) == typeof(int))
            {
                if (int.TryParse(value, out var resultInt))
                {
                    result = (T)(object)resultInt;
                    validationErrorMessage = null;
                    return true;
                }
                else
                {
                    result = default;
                    validationErrorMessage = "The chosen value is not a valid number.";
                    return false;
                }
            }
            else
            {
                return base.TryParseValueFromString(value, out result, out validationErrorMessage);
            }
        }
    }
  

Обновить

Я могу привязать его, но он не учитывает требуемый атрибут, проверка не выполняется

Пожалуйста, запустите приведенный ниже код, введите значение для поля name, затем нажмите кнопку «Отправить». Форма «отправлена». Теперь выберите страну, а затем выберите «Выберите свою страну:»… отображается сообщение о проверке. Вывод: проверка выполняется только в том случае, если значение было ранее выбрано, а затем удалено. Я не знаю, является ли это поведение преднамеренным или ошибкой. Однако я придерживаюсь мнения, что такое поведение не связано с Blazor. Необходимо проверить, как элемент select с обязательным атрибутом ведет себя на страницах Razor. В любом случае, я попытаюсь устранить эту ошибку, и если это удастся, я дам вам знать…

 @using System.ComponentModel.DataAnnotations;
 
<EditForm EditContext="@EditContext" OnValidSubmit="HandleValidSubmit">
    <DataAnnotationsValidator />

    <div class="form-group">
        <label for="name">Enter your Name: </label>
        <InputText Id="name" Class="form-control" @bind-Value="@comment.Name"></InputText>
        <ValidationMessage For="@(() => comment.Name)" />

    </div>
    <div class="form-group">
        <label for="body">Select your country: </label>

        <InputSelect @bind-Value="@comment.Country" >
            <option value="0">Select country...</option>
            @foreach (var country in Enum.GetValues(typeof(Country)))
            {
            
                <option value="@country">@country</option>
            }
        </InputSelect>
               
        <ValidationMessage For="@(() => comment.Country)" />
    </div>

    <p>
        <button type="submit">Submit</button>
    </p>
</EditForm>


@code
    {
    private EditContext EditContext;
    private Comment comment = new Comment();

    private void HandleValidSubmit()
    {
        Console.WriteLine("Submitting");
    }
    protected override void OnInitialized()
    {
        EditContext = new EditContext(comment);


        base.OnInitialized();
    }

    public enum Country
    {
        USA = 1,
        Britain,
        Germany,
        Israel

    }
    public class Comment
    {
        [Required]
        public string Name { get; set; }
        [Required]
        public Country Country { get; set; }
    }

}   
  

Комментарии:

1. В .NET 5 InputSelect действительно может привязываться к int. Однако я столкнулся с этой проблемой в .NET 3.1 с помощью InputSelect, связанного с перечислением.

2. Вы имеете в виду, что вы не смогли привязать свой selectinput к типу enum ? Если это так, это странно.

3.Я могу привязать его, но он не учитывает требуемый атрибут, проверка не выполняется

4. Проводя собственное исследование, я пришел практически к тому же выводу. Интересно, должен ли я отправить ошибку github

5. Да, вы можете отправить сообщение о проблеме в github, но это не значит, что это проблема только с перечисляемыми типами. Если вы используете привязку к строковому типу, как, например, проверка выполняется, как только вы нажимаете кнопку «Отправить», если вам не удалось выбрать значение.

Ответ №2:

Быстрым и грязным обходным путем было бы использовать Range атрибут для перечисления в вашей модели. Однако вы должны присвоить числовые значения своему перечислению и использовать атрибут на их основе. Это определенно не лучшее решение, но это то, что работает для меня временно. Если кто-нибудь найдет лучшее решение, пожалуйста, поделитесь им.

Пример:

 public class SomeModel
{
    [Required]
    public string SomeString { get; set; }

    [Required]
    [Range(1, int.MaxValue)]
    public SomeEnum SomeEnum { get; set; }

    [Required]
    public SomeEnum? SomeNullableEnum { get; set; }

    [Required]
    public int SomeInt { get; set; }

    [Required]
    public int? SomeNullableInt { get; set; }
}

public enum SomeEnum
{
    A = 1,
    B = 2
}
  

Комментарии:

1. Ха, это умно!