Commit 56ba1ef1 authored by 阿星Plus's avatar 阿星Plus

Validation Interceptor Registrar

parent 6e8bd479
using Plus.Collections;
using Plus.Service;
using System;
namespace Plus.Aspects
{
internal class PlusCrossCuttingConcerns
{
public const string Validation = "PlusValidation";
public const string UnitOfWork = "PlusUnitOfWork";
public static void AddApplied(object obj, params string[] concerns)
{
if (concerns.IsNullOrEmpty())
{
throw new ArgumentNullException(nameof(concerns), $"{nameof(concerns)} should be provided!");
}
(obj as IAvoidDuplicateCrossCuttingConcerns)?.AppliedCrossCuttingConcerns.AddRange(concerns);
}
public static void RemoveApplied(object obj, params string[] concerns)
{
if (concerns.IsNullOrEmpty())
{
throw new ArgumentNullException(nameof(concerns), $"{nameof(concerns)} should be provided!");
}
if (obj is IAvoidDuplicateCrossCuttingConcerns avoidDuplicateCrossCuttingConcerns)
{
foreach (string concern in concerns)
{
avoidDuplicateCrossCuttingConcerns.AppliedCrossCuttingConcerns.RemoveAll((string c) => c == concern);
}
}
}
public static bool IsApplied(object obj, string concern)
{
if (obj == null)
{
throw new ArgumentNullException("obj");
}
if (concern == null)
{
throw new ArgumentNullException("concern");
}
return (obj as IAvoidDuplicateCrossCuttingConcerns)?.AppliedCrossCuttingConcerns.Contains(concern) ?? false;
}
public static IDisposable Applying(object obj, params string[] concerns)
{
AddApplied(obj, concerns);
return new DisposeAction(() =>
{
RemoveApplied(obj, concerns);
});
}
public static string[] GetApplieds(object obj)
{
if (!(obj is IAvoidDuplicateCrossCuttingConcerns crossCuttingEnabledObj))
{
return new string[0];
}
return crossCuttingEnabledObj.AppliedCrossCuttingConcerns.ToArray();
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
namespace Plus.Collections
{
public interface ITypeList : ITypeList<object>
{
}
public interface ITypeList<in TBaseType> : IList<Type>
{
void Add<T>() where T : TBaseType;
bool Contains<T>() where T : TBaseType;
void Remove<T>() where T : TBaseType;
}
}
\ No newline at end of file
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
namespace Plus.Collections
{
public class TypeList : TypeList<object>, ITypeList
{
}
public class TypeList<TBaseType> : ITypeList<TBaseType>
{
public int Count { get { return _typeList.Count; } }
public bool IsReadOnly { get { return false; } }
public Type this[int index]
{
get { return _typeList[index]; }
set
{
CheckType(value);
_typeList[index] = value;
}
}
private readonly List<Type> _typeList;
public TypeList()
{
_typeList = new List<Type>();
}
public void Add<T>() where T : TBaseType
{
_typeList.Add(typeof(T));
}
public void Add(Type item)
{
CheckType(item);
_typeList.Add(item);
}
public void Insert(int index, Type item)
{
_typeList.Insert(index, item);
}
public int IndexOf(Type item)
{
return _typeList.IndexOf(item);
}
public bool Contains<T>() where T : TBaseType
{
return Contains(typeof(T));
}
public bool Contains(Type item)
{
return _typeList.Contains(item);
}
public void Remove<T>() where T : TBaseType
{
_typeList.Remove(typeof(T));
}
public bool Remove(Type item)
{
return _typeList.Remove(item);
}
public void RemoveAt(int index)
{
_typeList.RemoveAt(index);
}
public void Clear()
{
_typeList.Clear();
}
public void CopyTo(Type[] array, int arrayIndex)
{
_typeList.CopyTo(array, arrayIndex);
}
public IEnumerator<Type> GetEnumerator()
{
return _typeList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _typeList.GetEnumerator();
}
private static void CheckType(Type item)
{
if (!typeof(TBaseType).GetTypeInfo().IsAssignableFrom(item))
{
throw new ArgumentException("Given item is not type of " + typeof(TBaseType).AssemblyQualifiedName, "item");
}
}
}
}
\ No newline at end of file
using Plus.Collections;
using Plus.Runtime.Validation.Interception;
using System;
using System.Collections.Generic;
namespace Plus.Configuration.Startup
{
public interface IValidationConfiguration
{
List<Type> IgnoredTypes { get; }
/// <summary>
/// 方法参数验证器的列表
/// </summary>
ITypeList<IMethodParameterValidator> Validators { get; }
}
}
\ No newline at end of file
using System;
using System.Threading;
namespace Plus
{
/// <summary>
/// 这个类可用于在调用Dipose方法时提供一个操作
/// </summary>
public class DisposeAction : IDisposable
{
public static readonly DisposeAction Empty = new DisposeAction(null);
private Action _action;
/// <summary>
/// 创建一个新的 <see cref="DisposeAction"/> 对象。
/// </summary>
/// <param name="action"></param>
public DisposeAction(Action action)
{
_action = action;
}
public void Dispose()
{
Interlocked.Exchange(ref _action, null)?.Invoke();
}
}
}
\ No newline at end of file
namespace Plus.Logging
{
public interface IHasLogSeverity
{
LogSeverity Severity { get; set; }
}
}
\ No newline at end of file
namespace Plus.Logging
{
public enum LogSeverity
{
Debug,
Info,
Warn,
Error,
Fatal
}
}
\ No newline at end of file
......@@ -8,6 +8,7 @@
<PackageReference Include="Castle.Core" Version="4.4.0" />
<PackageReference Include="Castle.Windsor" Version="5.0.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
</ItemGroup>
</Project>
......@@ -4,6 +4,7 @@ using Plus.Configuration.Startup;
using Plus.Dependency;
using Plus.Dependency.Installers;
using Plus.Modules;
using Plus.Runtime.Validation.Interception;
using System;
using System.Reflection;
......@@ -97,7 +98,7 @@ namespace Plus
public void AddInterceptorRegistrars()
{
//ValidationInterceptorRegistrar.Initialize(IocManager);
ValidationInterceptorRegistrar.Initialize(IocManager);
//UnitOfWorkRegistrar.Initialize(IocManager);
}
}
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Plus.Reflection
{
/// <summary>
/// 反射帮助类
/// </summary>
internal static class ReflectionHelper
{
/// <summary>
/// Checks whether <paramref name="givenType"/> implements/inherits <paramref name="genericType"/>.
/// </summary>
/// <param name="givenType">Type to check</param>
/// <param name="genericType">Generic type</param>
public static bool IsAssignableToGenericType(Type givenType, Type genericType)
{
var givenTypeInfo = givenType.GetTypeInfo();
if (givenTypeInfo.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
{
return true;
}
foreach (var interfaceType in givenType.GetInterfaces())
{
if (interfaceType.GetTypeInfo().IsGenericType && interfaceType.GetGenericTypeDefinition() == genericType)
{
return true;
}
}
if (givenTypeInfo.BaseType == null)
{
return false;
}
return IsAssignableToGenericType(givenTypeInfo.BaseType, genericType);
}
/// <summary>
/// Gets a list of attributes defined for a class member and it's declaring type including inherited attributes.
/// </summary>
/// <param name="inherit">Inherit attribute from base classes</param>
/// <param name="memberInfo">MemberInfo</param>
public static List<object> GetAttributesOfMemberAndDeclaringType(MemberInfo memberInfo, bool inherit = true)
{
var attributeList = new List<object>();
attributeList.AddRange(memberInfo.GetCustomAttributes(inherit));
if (memberInfo.DeclaringType != null)
{
attributeList.AddRange(memberInfo.DeclaringType.GetTypeInfo().GetCustomAttributes(inherit));
}
return attributeList;
}
/// <summary>
/// Gets a list of attributes defined for a class member and type including inherited attributes.
/// </summary>
/// <param name="memberInfo">MemberInfo</param>
/// <param name="type">Type</param>
/// <param name="inherit">Inherit attribute from base classes</param>
public static List<object> GetAttributesOfMemberAndType(MemberInfo memberInfo, Type type, bool inherit = true)
{
var attributeList = new List<object>();
attributeList.AddRange(memberInfo.GetCustomAttributes(inherit));
attributeList.AddRange(type.GetTypeInfo().GetCustomAttributes(inherit));
return attributeList;
}
/// <summary>
/// Gets a list of attributes defined for a class member and it's declaring type including inherited attributes.
/// </summary>
/// <typeparam name="TAttribute">Type of the attribute</typeparam>
/// <param name="memberInfo">MemberInfo</param>
/// <param name="inherit">Inherit attribute from base classes</param>
public static List<TAttribute> GetAttributesOfMemberAndDeclaringType<TAttribute>(MemberInfo memberInfo, bool inherit = true)
where TAttribute : Attribute
{
var attributeList = new List<TAttribute>();
if (memberInfo.IsDefined(typeof(TAttribute), inherit))
{
attributeList.AddRange(memberInfo.GetCustomAttributes(typeof(TAttribute), inherit).Cast<TAttribute>());
}
if (memberInfo.DeclaringType != null && memberInfo.DeclaringType.GetTypeInfo().IsDefined(typeof(TAttribute), inherit))
{
attributeList.AddRange(memberInfo.DeclaringType.GetTypeInfo().GetCustomAttributes(typeof(TAttribute), inherit).Cast<TAttribute>());
}
return attributeList;
}
/// <summary>
/// Gets a list of attributes defined for a class member and type including inherited attributes.
/// </summary>
/// <typeparam name="TAttribute">Type of the attribute</typeparam>
/// <param name="memberInfo">MemberInfo</param>
/// <param name="type">Type</param>
/// <param name="inherit">Inherit attribute from base classes</param>
public static List<TAttribute> GetAttributesOfMemberAndType<TAttribute>(MemberInfo memberInfo, Type type, bool inherit = true)
where TAttribute : Attribute
{
var attributeList = new List<TAttribute>();
if (memberInfo.IsDefined(typeof(TAttribute), inherit))
{
attributeList.AddRange(memberInfo.GetCustomAttributes(typeof(TAttribute), inherit).Cast<TAttribute>());
}
if (type.GetTypeInfo().IsDefined(typeof(TAttribute), inherit))
{
attributeList.AddRange(type.GetTypeInfo().GetCustomAttributes(typeof(TAttribute), inherit).Cast<TAttribute>());
}
return attributeList;
}
/// <summary>
/// Tries to gets an of attribute defined for a class member and it's declaring type including inherited attributes.
/// Returns default value if it's not declared at all.
/// </summary>
/// <typeparam name="TAttribute">Type of the attribute</typeparam>
/// <param name="memberInfo">MemberInfo</param>
/// <param name="defaultValue">Default value (null as default)</param>
/// <param name="inherit">Inherit attribute from base classes</param>
public static TAttribute GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<TAttribute>(MemberInfo memberInfo, TAttribute defaultValue = default(TAttribute), bool inherit = true)
where TAttribute : class
{
return memberInfo.GetCustomAttributes(true).OfType<TAttribute>().FirstOrDefault()
?? memberInfo.ReflectedType?.GetTypeInfo().GetCustomAttributes(true).OfType<TAttribute>().FirstOrDefault()
?? defaultValue;
}
/// <summary>
/// Tries to gets an of attribute defined for a class member and it's declaring type including inherited attributes.
/// Returns default value if it's not declared at all.
/// </summary>
/// <typeparam name="TAttribute">Type of the attribute</typeparam>
/// <param name="memberInfo">MemberInfo</param>
/// <param name="defaultValue">Default value (null as default)</param>
/// <param name="inherit">Inherit attribute from base classes</param>
public static TAttribute GetSingleAttributeOrDefault<TAttribute>(MemberInfo memberInfo, TAttribute defaultValue = default(TAttribute), bool inherit = true)
where TAttribute : Attribute
{
//Get attribute on the member
if (memberInfo.IsDefined(typeof(TAttribute), inherit))
{
return memberInfo.GetCustomAttributes(typeof(TAttribute), inherit).Cast<TAttribute>().First();
}
return defaultValue;
}
/// <summary>
/// Gets a property by it's full path from given object
/// </summary>
/// <param name="obj">Object to get value from</param>
/// <param name="objectType">Type of given object</param>
/// <param name="propertyPath">Full path of property</param>
/// <returns></returns>
internal static object GetPropertyByPath(object obj, Type objectType, string propertyPath)
{
var property = obj;
var currentType = objectType;
var objectPath = currentType.FullName;
var absolutePropertyPath = propertyPath;
if (absolutePropertyPath.StartsWith(objectPath))
{
absolutePropertyPath = absolutePropertyPath.Replace(objectPath + ".", "");
}
foreach (var propertyName in absolutePropertyPath.Split('.'))
{
property = currentType.GetProperty(propertyName);
currentType = ((PropertyInfo)property).PropertyType;
}
return property;
}
/// <summary>
/// Gets value of a property by it's full path from given object
/// </summary>
/// <param name="obj">Object to get value from</param>
/// <param name="objectType">Type of given object</param>
/// <param name="propertyPath">Full path of property</param>
/// <returns></returns>
internal static object GetValueByPath(object obj, Type objectType, string propertyPath)
{
var value = obj;
var currentType = objectType;
var objectPath = currentType.FullName;
var absolutePropertyPath = propertyPath;
if (absolutePropertyPath.StartsWith(objectPath))
{
absolutePropertyPath = absolutePropertyPath.Replace(objectPath + ".", "");
}
foreach (var propertyName in absolutePropertyPath.Split('.'))
{
var property = currentType.GetProperty(propertyName);
value = property.GetValue(value, null);
currentType = property.PropertyType;
}
return value;
}
/// <summary>
/// Sets value of a property by it's full path on given object
/// </summary>
/// <param name="obj"></param>
/// <param name="objectType"></param>
/// <param name="propertyPath"></param>
/// <param name="value"></param>
internal static void SetValueByPath(object obj, Type objectType, string propertyPath, object value)
{
var currentType = objectType;
PropertyInfo property;
var objectPath = currentType.FullName;
var absolutePropertyPath = propertyPath;
if (absolutePropertyPath.StartsWith(objectPath))
{
absolutePropertyPath = absolutePropertyPath.Replace(objectPath + ".", "");
}
var properties = absolutePropertyPath.Split('.');
if (properties.Length == 1)
{
property = objectType.GetProperty(properties.First());
property.SetValue(obj, value);
return;
}
for (int i = 0; i < properties.Length - 1; i++)
{
property = currentType.GetProperty(properties[i]);
obj = property.GetValue(obj, null);
currentType = property.PropertyType;
}
property = currentType.GetProperty(properties.Last());
property.SetValue(obj, value);
}
internal static bool IsPropertyGetterSetterMethod(MethodInfo method, Type type)
{
if (!method.IsSpecialName)
{
return false;
}
if (method.Name.Length < 5)
{
return false;
}
return type.GetProperty(method.Name.Substring(4), BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic) != null;
}
}
}
\ No newline at end of file
using System;
using System.Reflection;
namespace Plus.Reflection
{
/// <summary>
/// 一些内部使用的简单类型检查方法
/// </summary>
internal static class TypeHelper
{
public static bool IsFunc(object obj)
{
if (obj == null)
{
return false;
}
var type = obj.GetType();
if (!type.GetTypeInfo().IsGenericType)
{
return false;
}
return type.GetGenericTypeDefinition() == typeof(Func<>);
}
public static bool IsFunc<TReturn>(object obj)
{
return obj != null && obj.GetType() == typeof(Func<TReturn>);
}
public static bool IsPrimitiveExtendedIncludingNullable(Type type, bool includeEnums = false)
{
if (IsPrimitiveExtended(type, includeEnums))
{
return true;
}
if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
return IsPrimitiveExtended(type.GenericTypeArguments[0], includeEnums);
}
return false;
}
private static bool IsPrimitiveExtended(Type type, bool includeEnums)
{
if (type.GetTypeInfo().IsPrimitive)
{
return true;
}
if (includeEnums && type.GetTypeInfo().IsEnum)
{
return true;
}
return type == typeof(string) ||
type == typeof(decimal) ||
type == typeof(DateTime) ||
type == typeof(DateTimeOffset) ||
type == typeof(TimeSpan) ||
type == typeof(Guid);
}
}
}
\ No newline at end of file
using System;
namespace Plus.Runtime.Validation
{
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Property)]
public class DisableValidationAttribute : Attribute
{
}
}
\ No newline at end of file
using System;
namespace Plus.Runtime.Validation
{
[AttributeUsage(AttributeTargets.Method)]
public class EnableValidationAttribute : Attribute
{
}
}
\ No newline at end of file
namespace Plus.Runtime.Validation
{
/// <summary>
/// 此接口用于在方法执行之前对输入进行规范化
/// </summary>
public interface IShouldNormalize
{
/// <summary>
/// 方法最后在方法执行之前调用(如果存在,则在验证之后调用)
/// </summary>
void Normalize();
}
}
\ No newline at end of file
using Plus.Dependency;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace Plus.Runtime.Validation.Interception
{
public interface IMethodParameterValidator : ITransientDependency
{
IReadOnlyList<ValidationResult> Validate(object validatingObject);
}
}
\ No newline at end of file
using Plus.Dependency;
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using Plus;
using Plus.Configuration.Startup;
using Plus.Runtime.Validation;
using Plus.Runtime.Validation.Interception;
using System.ComponentModel.DataAnnotations;
using Plus.Collections;
using Plus.Reflection;
namespace Plus.Runtime.Validation.Interception
{
/// <summary>
/// 该类用于验证方法参数
/// </summary>
public class MethodInvocationValidator : ITransientDependency
{
private const int MaxRecursiveParameterValidationDepth = 8;
protected MethodInfo Method { get; private set; }
protected object[] ParameterValues { get; private set; }
protected ParameterInfo[] Parameters { get; private set; }
protected List<ValidationResult> ValidationErrors { get; }
protected List<IShouldNormalize> ObjectsToBeNormalized { get; }
private readonly IValidationConfiguration _configuration;
private readonly IIocResolver _iocResolver;
/// <summary>
/// Creates a new <see cref="MethodInvocationValidator"/> instance.
/// </summary>
public MethodInvocationValidator(IValidationConfiguration configuration, IIocResolver iocResolver)
{
_configuration = configuration;
_iocResolver = iocResolver;
ValidationErrors = new List<ValidationResult>();
ObjectsToBeNormalized = new List<IShouldNormalize>();
}
/// <param name="method">Method to be validated</param>
/// <param name="parameterValues">List of arguments those are used to call the <paramref name="method"/>.</param>
public virtual void Initialize(MethodInfo method, object[] parameterValues)
{
Method = method;
ParameterValues = parameterValues;
Parameters = method.GetParameters();
}
/// <summary>
/// Validates the method invocation.
/// </summary>
public void Validate()
{
CheckInitialized();
if (Parameters.IsNullOrEmpty())
{
return;
}
if (!Method.IsPublic)
{
return;
}
if (IsValidationDisabled())
{
return;
}
if (Parameters.Length != ParameterValues.Length)
{
throw new Exception("Method parameter count does not match with argument count!");
}
for (var i = 0; i < Parameters.Length; i++)
{
ValidateMethodParameter(Parameters[i], ParameterValues[i]);
}
if (ValidationErrors.Any())
{
ThrowValidationError();
}
foreach (var objectToBeNormalized in ObjectsToBeNormalized)
{
objectToBeNormalized.Normalize();
}
}
protected virtual void CheckInitialized()
{
if (Method == null)
{
throw new PlusException("This object has not been initialized. Call Initialize method first.");
}
}
protected virtual bool IsValidationDisabled()
{
if (Method.IsDefined(typeof(EnableValidationAttribute), true))
{
return false;
}
return ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<DisableValidationAttribute>(Method) != null;
}
protected virtual void ThrowValidationError()
{
throw new PlusValidationException("方法参数是无效的!有关详细信息,请参阅ValidationErrors:", ValidationErrors);
}
/// <summary>
/// Validates given parameter for given value.
/// </summary>
/// <param name="parameterInfo">Parameter of the method to validate</param>
/// <param name="parameterValue">Value to validate</param>
protected virtual void ValidateMethodParameter(ParameterInfo parameterInfo, object parameterValue)
{
if (parameterValue == null)
{
if (!parameterInfo.IsOptional &&
!parameterInfo.IsOut &&
!TypeHelper.IsPrimitiveExtendedIncludingNullable(parameterInfo.ParameterType, includeEnums: true))
{
ValidationErrors.Add(new ValidationResult(parameterInfo.Name + " is null!", new[] { parameterInfo.Name }));
}
return;
}
ValidateObjectRecursively(parameterValue, 1);
}
protected virtual void ValidateObjectRecursively(object validatingObject, int currentDepth)
{
if (currentDepth > MaxRecursiveParameterValidationDepth)
{
return;
}
if (validatingObject == null)
{
return;
}
if (_configuration.IgnoredTypes.Any(t => t.IsInstanceOfType(validatingObject)))
{
return;
}
if (TypeHelper.IsPrimitiveExtendedIncludingNullable(validatingObject.GetType()))
{
return;
}
SetValidationErrors(validatingObject);
// Validate items of enumerable
if (IsEnumerable(validatingObject))
{
foreach (var item in (IEnumerable)validatingObject)
{
ValidateObjectRecursively(item, currentDepth + 1);
}
}
// Add list to be normalized later
if (validatingObject is IShouldNormalize)
{
ObjectsToBeNormalized.Add(validatingObject as IShouldNormalize);
}
if (ShouldMakeDeepValidation(validatingObject))
{
var properties = TypeDescriptor.GetProperties(validatingObject).Cast<PropertyDescriptor>();
foreach (var property in properties)
{
if (property.Attributes.OfType<DisableValidationAttribute>().Any())
{
continue;
}
ValidateObjectRecursively(property.GetValue(validatingObject), currentDepth + 1);
}
}
}
protected virtual void SetValidationErrors(object validatingObject)
{
foreach (var validatorType in _configuration.Validators)
{
if (ShouldValidateUsingValidator(validatingObject, validatorType))
{
using (var validator = _iocResolver.ResolveAsDisposable<IMethodParameterValidator>(validatorType))
{
var validationResults = validator.Object.Validate(validatingObject);
ValidationErrors.AddRange(validationResults);
}
}
}
}
protected virtual bool ShouldValidateUsingValidator(object validatingObject, Type validatorType)
{
return true;
}
protected virtual bool ShouldMakeDeepValidation(object validatingObject)
{
// Do not recursively validate for enumerable objects
if (validatingObject is IEnumerable)
{
return false;
}
var validatingObjectType = validatingObject.GetType();
// Do not recursively validate for primitive objects
if (TypeHelper.IsPrimitiveExtendedIncludingNullable(validatingObjectType))
{
return false;
}
return true;
}
private bool IsEnumerable(object validatingObject)
{
return
validatingObject is IEnumerable &&
!(validatingObject is IQueryable) &&
!TypeHelper.IsPrimitiveExtendedIncludingNullable(validatingObject.GetType());
}
}
}
\ No newline at end of file
using Castle.DynamicProxy;
using Plus.Aspects;
using Plus.Dependency;
namespace Plus.Runtime.Validation.Interception
{
/// <summary>
/// 这个拦截器用于拦截类的方法调用,类的方法必须经过验证。
/// </summary>
public class ValidationInterceptor : IInterceptor
{
private readonly IIocResolver _iocResolver;
public ValidationInterceptor(IIocResolver iocResolver)
{
_iocResolver = iocResolver;
}
public void Intercept(IInvocation invocation)
{
if (PlusCrossCuttingConcerns.IsApplied(invocation.InvocationTarget, PlusCrossCuttingConcerns.Validation))
{
invocation.Proceed();
return;
}
using (var validator = _iocResolver.ResolveAsDisposable<MethodInvocationValidator>())
{
validator.Object.Initialize(invocation.MethodInvocationTarget, invocation.Arguments);
validator.Object.Validate();
}
invocation.Proceed();
}
}
}
\ No newline at end of file
using Castle.Core;
using Castle.MicroKernel;
using Plus.Dependency;
using Plus.Service;
using System.Reflection;
namespace Plus.Runtime.Validation.Interception
{
internal static class ValidationInterceptorRegistrar
{
public static void Initialize(IIocManager iocManager)
{
iocManager.IocContainer.Kernel.ComponentRegistered += Kernel_ComponentRegistered;
}
private static void Kernel_ComponentRegistered(string key, IHandler handler)
{
if (typeof(IApplicationService).GetTypeInfo().IsAssignableFrom(handler.ComponentModel.Implementation))
{
handler.ComponentModel.Interceptors.Add(new InterceptorReference(typeof(ValidationInterceptor)));
}
}
}
}
\ No newline at end of file
using Plus.Logging;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Runtime.Serialization;
namespace Plus.Runtime.Validation
{
[Serializable]
public class PlusValidationException : PlusException, IHasLogSeverity
{
public IList<ValidationResult> ValidationErrors { get; set; }
public LogSeverity Severity { get; set; }
public PlusValidationException()
{
ValidationErrors = new List<ValidationResult>();
Severity = LogSeverity.Warn;
}
public PlusValidationException(SerializationInfo serializationInfo, StreamingContext context)
: base(serializationInfo, context)
{
ValidationErrors = new List<ValidationResult>();
Severity = LogSeverity.Warn;
}
public PlusValidationException(string message)
: base(message)
{
ValidationErrors = new List<ValidationResult>();
Severity = LogSeverity.Warn;
}
public PlusValidationException(string message, IList<ValidationResult> validationErrors)
: base(message)
{
ValidationErrors = validationErrors;
Severity = LogSeverity.Warn;
}
public PlusValidationException(string message, Exception innerException)
: base(message, innerException)
{
ValidationErrors = new List<ValidationResult>();
Severity = LogSeverity.Warn;
}
}
}
\ No newline at end of file
using Plus.Dependency;
namespace Plus.Service
{
interface IApplicationService : ITransientDependency
{
}
}
\ No newline at end of file
using System.Collections.Generic;
namespace Plus.Service
{
public interface IAvoidDuplicateCrossCuttingConcerns
{
List<string> AppliedCrossCuttingConcerns { get; }
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment