Browse Source

Allow to write custom code to validate an extensible object.

pull/3561/head
Halil İbrahim Kalkan 6 years ago
parent
commit
c69e2f12ed
  1. 79
      framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObjectValidator.cs
  2. 4
      framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs
  3. 4
      framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs
  4. 61
      framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyValidationContext.cs
  5. 53
      framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionValidationContext.cs
  6. 73
      framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ExtensibleObjectValidator_Tests.cs

79
framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ExtensibleObjectValidator.cs

@ -52,20 +52,47 @@ namespace Volo.Abp.ObjectExtending
return;
}
foreach (var propertyInfo in objectExtensionInfo.GetProperties())
AddPropertyValidationErrors(
extensibleObject,
validationErrors,
objectValidationContext,
objectExtensionInfo
);
ExecuteCustomObjectValidationActions(
extensibleObject,
validationErrors,
objectValidationContext,
objectExtensionInfo
);
}
private static void AddPropertyValidationErrors(
IHasExtraProperties extensibleObject,
List<ValidationResult> validationErrors,
ValidationContext objectValidationContext,
ObjectExtensionInfo objectExtensionInfo)
{
var properties = objectExtensionInfo.GetProperties();
if (!properties.Any())
{
return;
}
foreach (var property in properties)
{
if (propertyInfo.ValidationAttributes.Any())
if (property.ValidationAttributes.Any())
{
var propertyValidationContext = new ValidationContext(extensibleObject, objectValidationContext, null)
{
DisplayName = propertyInfo.Name,
MemberName = propertyInfo.Name
DisplayName = property.Name,
MemberName = property.Name
};
foreach (var attribute in propertyInfo.ValidationAttributes)
foreach (var attribute in property.ValidationAttributes)
{
var result = attribute.GetValidationResult(
extensibleObject.GetProperty(propertyInfo.Name),
extensibleObject.GetProperty(property.Name),
propertyValidationContext
);
if (result != null)
@ -74,6 +101,46 @@ namespace Volo.Abp.ObjectExtending
}
}
}
if (property.Validators.Any())
{
var context = new ObjectExtensionPropertyValidationContext(
property,
extensibleObject,
validationErrors,
objectValidationContext,
extensibleObject.GetProperty(property.Name)
);
foreach (var validator in property.Validators)
{
validator(context);
}
}
}
}
private static void ExecuteCustomObjectValidationActions(
IHasExtraProperties extensibleObject,
List<ValidationResult> validationErrors,
ValidationContext objectValidationContext,
ObjectExtensionInfo objectExtensionInfo)
{
if (!objectExtensionInfo.Validators.Any())
{
return;
}
var context = new ObjectExtensionValidationContext(
objectExtensionInfo,
extensibleObject,
validationErrors,
objectValidationContext
);
foreach (var validator in objectExtensionInfo.Validators)
{
validator(context);
}
}
}

4
framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionInfo.cs

@ -17,11 +17,15 @@ namespace Volo.Abp.ObjectExtending
[NotNull]
public Dictionary<object, object> Configuration { get; }
[NotNull]
public List<Action<ObjectExtensionValidationContext>> Validators { get; }
public ObjectExtensionInfo([NotNull] Type type)
{
Type = Check.AssignableTo<IHasExtraProperties>(type, nameof(type));
Properties = new Dictionary<string, ObjectExtensionPropertyInfo>();
Configuration = new Dictionary<object, object>();
Validators = new List<Action<ObjectExtensionValidationContext>>();
}
public virtual bool HasProperty(string propertyName)

4
framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs

@ -19,6 +19,9 @@ namespace Volo.Abp.ObjectExtending
[NotNull]
public List<ValidationAttribute> ValidationAttributes { get; }
[NotNull]
public List<Action<ObjectExtensionPropertyValidationContext>> Validators { get; }
/// <summary>
/// Indicates whether to check the other side of the object mapping
/// if it explicitly defines the property. This property is used in;
@ -47,6 +50,7 @@ namespace Volo.Abp.ObjectExtending
Configuration = new Dictionary<object, object>();
ValidationAttributes = new List<ValidationAttribute>();
Validators = new List<Action<ObjectExtensionPropertyValidationContext>>();
}
}
}

61
framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyValidationContext.cs

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using JetBrains.Annotations;
using Volo.Abp.Data;
namespace Volo.Abp.ObjectExtending
{
public class ObjectExtensionPropertyValidationContext
{
/// <summary>
/// Related property extension information.
/// </summary>
[NotNull]
public ObjectExtensionPropertyInfo ExtensionPropertyInfo { get; }
/// <summary>
/// Reference to the validating object.
/// </summary>
[NotNull]
public IHasExtraProperties ValidatingObject { get; }
/// <summary>
/// Add validation errors to this list.
/// </summary>
[NotNull]
public List<ValidationResult> ValidationErrors { get; }
/// <summary>
/// Validation context comes from the <see cref="IValidatableObject.Validate"/> method.
/// </summary>
[NotNull]
public ValidationContext ValidationContext { get; }
/// <summary>
/// The value of the validating property of the <see cref="ValidatingObject"/>.
/// </summary>
[CanBeNull]
public object Value { get; }
/// <summary>
/// Can be used to resolve services from the dependency injection container.
/// </summary>
[CanBeNull]
public IServiceProvider ServiceProvider => ValidationContext;
public ObjectExtensionPropertyValidationContext(
[NotNull] ObjectExtensionPropertyInfo objectExtensionPropertyInfo,
[NotNull] IHasExtraProperties validatingObject,
[NotNull] List<ValidationResult> validationErrors,
[NotNull] ValidationContext validationContext,
[CanBeNull] object value)
{
ExtensionPropertyInfo = Check.NotNull(objectExtensionPropertyInfo, nameof(objectExtensionPropertyInfo));
ValidatingObject = Check.NotNull(validatingObject, nameof(validatingObject));
ValidationErrors = Check.NotNull(validationErrors, nameof(validationErrors));
ValidationContext = Check.NotNull(validationContext, nameof(validationContext));
Value = value;
}
}
}

53
framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionValidationContext.cs

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using JetBrains.Annotations;
using Volo.Abp.Data;
namespace Volo.Abp.ObjectExtending
{
public class ObjectExtensionValidationContext
{
/// <summary>
/// Related object extension information.
/// </summary>
[NotNull]
public ObjectExtensionInfo ObjectExtensionInfo { get; }
/// <summary>
/// Reference to the validating object.
/// </summary>
[NotNull]
public IHasExtraProperties ValidatingObject { get; }
/// <summary>
/// Add validation errors to this list.
/// </summary>
[NotNull]
public List<ValidationResult> ValidationErrors { get; }
/// <summary>
/// Validation context comes from the <see cref="IValidatableObject.Validate"/> method.
/// </summary>
[NotNull]
public ValidationContext ValidationContext { get; }
/// <summary>
/// Can be used to resolve services from the dependency injection container.
/// </summary>
[CanBeNull]
public IServiceProvider ServiceProvider => ValidationContext;
public ObjectExtensionValidationContext(
[NotNull] ObjectExtensionInfo objectExtensionInfo,
[NotNull] IHasExtraProperties validatingObject,
[NotNull] List<ValidationResult> validationErrors,
[NotNull] ValidationContext validationContext)
{
ObjectExtensionInfo = Check.NotNull(objectExtensionInfo, nameof(objectExtensionInfo));
ValidatingObject = Check.NotNull(validatingObject, nameof(validatingObject));
ValidationErrors = Check.NotNull(validationErrors, nameof(validationErrors));
ValidationContext = Check.NotNull(validationContext, nameof(validationContext));
}
}
}

73
framework/test/Volo.Abp.ObjectExtending.Tests/Volo/Abp/ObjectExtending/ExtensibleObjectValidator_Tests.cs

@ -38,6 +38,43 @@ namespace Volo.Abp.ObjectExtending
{
});
options.AddOrUpdateProperty<string>("Password", propertyInfo =>
{
});
options.AddOrUpdateProperty<string>("PasswordRepeat", propertyInfo =>
{
propertyInfo.Validators.Add(context =>
{
if (context.ValidatingObject.HasProperty("Password"))
{
if (context.ValidatingObject.GetProperty<string>("Password") !=
context.Value as string)
{
context.ValidationErrors.Add(
new ValidationResult(
"If you specify a password, then please correctly repeat it!",
new[] {"Password", "PasswordRepeat"}
)
);
}
}
});
});
options.Validators.Add(context =>
{
if (context.ValidatingObject.GetProperty<string>("Name") == "BadValue")
{
context.ValidationErrors.Add(
new ValidationResult(
"Name can not be 'BadValue', sorry :(",
new[] { "Name" }
)
);
}
});
});
});
}
@ -64,7 +101,7 @@ namespace Volo.Abp.ObjectExtending
ExtensibleObjectValidator
.GetValidationErrors(
new ExtensiblePersonObject()
).Count.ShouldBe(2); //Name & Age
).Count.ShouldBe(2); // Name & Age
ExtensibleObjectValidator
.GetValidationErrors(
@ -75,7 +112,7 @@ namespace Volo.Abp.ObjectExtending
{"Address", new string('x', 256) }
}
}
).Count.ShouldBe(3); //Name, Age & Address
).Count.ShouldBe(3); // Name, Age & Address
ExtensibleObjectValidator
.GetValidationErrors(
@ -86,7 +123,7 @@ namespace Volo.Abp.ObjectExtending
{"Age", "42" }
}
}
).Count.ShouldBe(1); //Name
).Count.ShouldBe(1); // Name
ExtensibleObjectValidator
.GetValidationErrors(
@ -97,8 +134,34 @@ namespace Volo.Abp.ObjectExtending
{"Address", new string('x', 256) },
{"Age", "100" }
}
}
).Count.ShouldBe(3); //Name, Age & Address
}
).Count.ShouldBe(3); // Name, Age & Address
ExtensibleObjectValidator
.GetValidationErrors(
new ExtensiblePersonObject
{
ExtraProperties =
{
{"Name", "John"},
{"Age", "42"},
{"Password", "123"},
{"PasswordRepeat", "1256"}
}
}
).Count.ShouldBe(1); // PasswordRepeat != Password
ExtensibleObjectValidator
.GetValidationErrors(
new ExtensiblePersonObject
{
ExtraProperties =
{
{"Name", "BadValue"},
{"Age", "42"},
}
}
).Count.ShouldBe(1); //Name is 'BadValue'!
}
private class ExtensiblePersonObject : ExtensibleObject

Loading…
Cancel
Save