定制类的Blazor验证

时间:2019-06-04 15:30:17

标签: c# validation .net-core blazor

我正在测试Blazor,但遇到了验证问题。当验证一个简单的类时,我可以只使用注释。如果我内部有自己的自定义类,尽管验证不会针对自定义类中的所有内容运行。这个问题似乎是Blazor特有的,因为我可以在ASP中使用此验证。

这是我的两个简单模型:

public class TestModel
{
    [Required]
    [Range(12, 400, ErrorMessage = "This works")]
    public int Count { get; set; }

    public KeyValue KeyValues { get; set; }
    public TestModel()
    {
        Count = 4;
        KeyValues = new KeyValue()
        {
            Key = 5,
            Value = "str"
        };
    }
}

还有KeyValue类

public class KeyValue
{
    [Required]
    [Range(10, 300, ErrorMessage = "This number check doesn't")]
    public int Key { get; set; }
    [Required]
    [StringLength(10, MinimumLength = 5, ErrorMessage = "Nor the string one")]
    public string Value { get; set; }
}

那是我的组成部分。它会验证Model.Count属性,但不会验证嵌套类。

<EditForm Model="@Model" OnValidSubmit="@DoStuff">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <div class="row">
        <div class="col-md-4">
            <input type="number" bind="@Model.Count" class="form-control" placeholder="Condition property name" />
        </div>
        <div class="col-md-4">
            <input type="number" bind="@Model.KeyValues.Key" class="form-control" placeholder="Condition property name" />
        </div>
        <div class="col-md-4">
            <InputText bind-Value="@Model.KeyValues.Value"></InputText>
        </div>

    </div>
    <div class="row">
        <div class="col-md-12">
            <button type="submit" class="btn btn-info">Create</button>
        </div>
    </div>
</EditForm>

2 个答案:

答案 0 :(得分:0)

如果其他人偶然发现了此问题,则目前无法实现。根据这篇文章,它应该在3.0.0-preview8中可用 https://github.com/aspnet/AspNetCore/issues/10896

答案 1 :(得分:0)

这是Blazor的已知限制,但是您可以解决它。

首先,在OnSubmit上使用<EditForm>事件,而不要使用OnValidSubmit。像这样通过EditContext传递方法...

private void FormSubmitted(EditContext context)
{
  ...
}

如果使用以下扩展名,则可以在FormSubmitted方法中使用以下代码,它不仅会验证整个对象树,还会根据结果更新UI。

{
  if (context.ValdiateObjectTree())
  {
    ... do whatever
  }
}

扩展名...

using Microsoft.AspNetCore.Components.Forms;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace PeterLeslieMorris.Blazor.Validation.Extensions
{
    public static class EditContextExtensions
    {
        static PropertyInfo IsModifiedProperty;
        static MethodInfo GetFieldStateMethod;

        /// <summary>
        /// Validates an entire object tree
        /// </summary>
        /// <param name="editContext">The EditContext to validate the Model of</param>
        /// <returns>True if valid, otherwise false</returns>
        public static bool ValidateObjectTree(this EditContext editContext)
        {
            var validatedObjects = new HashSet<object>();
            ValidateObject(editContext, editContext.Model, validatedObjects);
            editContext.NotifyValidationStateChanged();
            return !editContext.GetValidationMessages().Any();
        }

        public static void ValidateProperty(this EditContext editContext, FieldIdentifier fieldIdentifier)
        {
            if (fieldIdentifier.Model == null)
                return;

            var propertyInfo = fieldIdentifier.Model.GetType().GetProperty(
                fieldIdentifier.FieldName,
                BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static);

            var validatedObjects = new HashSet<object>();
            ValidateProperty(editContext, fieldIdentifier.Model, propertyInfo, validatedObjects);
        }

        private static void ValidateObject(
            EditContext editContext,
            object instance,
            HashSet<object> validatedObjects)
        {
            if (instance == null)
                return;

            if (validatedObjects.Contains(instance))
                return;

            if (instance is IEnumerable && !(instance is string))
            {
                foreach (object value in (IEnumerable)instance)
                    ValidateObject(editContext, value, validatedObjects);
                return;
            }

            if (instance.GetType().Assembly == typeof(string).Assembly)
                return;

            validatedObjects.Add(instance);

            var properties = instance.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            foreach (PropertyInfo property in properties)
                ValidateProperty(editContext, instance, property, validatedObjects);
        }

        private static void ValidateProperty(
            EditContext editContext,
            object instance,
            PropertyInfo property,
            HashSet<object> validatedObjects)
        {
            NotifyPropertyChanged(editContext, instance, property.Name);

            object value = property.GetValue(instance);
            ValidateObject(editContext, value, validatedObjects);
        }

        private static void NotifyPropertyChanged(
            EditContext editContext,
            object instance,
            string propertyName)
        {
            if (GetFieldStateMethod == null)
            {
                GetFieldStateMethod = editContext.GetType().GetMethod(
                    "GetFieldState",
                    BindingFlags.NonPublic | BindingFlags.Instance);
            }

            var fieldIdentifier = new FieldIdentifier(instance, propertyName);
            object fieldState = GetFieldStateMethod.Invoke(editContext, new object[] { fieldIdentifier, true });

            if (IsModifiedProperty == null)
            {
                IsModifiedProperty = fieldState.GetType().GetProperty(
                    "IsModified",
                    BindingFlags.Public | BindingFlags.Instance);
            }

            object originalIsModified = IsModifiedProperty.GetValue(fieldState);
            editContext.NotifyFieldChanged(fieldIdentifier);
            IsModifiedProperty.SetValue(fieldState, originalIsModified);
        }

    }
}

您可以找到扩展源here。您可以选择使用Blazor-Validation,也可以使用FluentValidation

如果您想更深入地了解Blazor表单/验证的工作原理,可以在Blazor University的本部分中进行阅读。