主要介紹ABP框架中攔截器的實現。在AbpBootstrapper中註冊ValidationInterceptorRegistrar驗證攔截器註冊對象,並初始化。app
/// <summary> /// 註冊攔截器 /// </summary> private void AddInterceptorRegistrars() { ValidationInterceptorRegistrar.Initialize(IocManager); }
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))); } }
若是符合條件,則添加ValidationInterceptor攔截器。函數
ValidationInterceptor的實現以下:
/// <summary> /// 驗證攔截器 /// </summary> public class ValidationInterceptor : IInterceptor { private readonly IIocResolver _iocResolver; public ValidationInterceptor(IIocResolver iocResolver) { this._iocResolver = iocResolver; } public void Intercept(IInvocation invocation) { using (var validator = _iocResolver.ResolveAsDisposable<MethodInvocationValidator>()) { validator.Object.Initialize(invocation.MethodInvocationTarget, invocation.Arguments); validator.Object.Validate(); } invocation.Proceed(); } }
主要經過MethodInvocationValidator中作些操做:this
public class MethodInvocationValidator : ITransientDependency { #region 聲明實例 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; } private readonly IIocResolver _iocResolver; private readonly IValidationConfiguration _configuration; #endregion #region 構造函數 public MethodInvocationValidator(IValidationConfiguration configuration, IIocResolver iocResolver) { _configuration = configuration; _iocResolver = iocResolver; ValidationErrors = new List<ValidationResult>(); } #endregion #region 方法 /// <summary> /// 要驗證的方法 /// </summary> /// <param name="method">方法</param> /// <param name="parameterValues">用於調用的參數列表</param> public virtual void Initialize(MethodInfo method, object[] parameterValues) { Method = method; ParameterValues = parameterValues; Parameters = method.GetParameters(); } 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!"); } if (ValidationErrors.Any() && HasSingleNullArgument()) { throw new Exception("Method arguments are not valid! See ValidationErrors for details!"); } for (var i = 0; i < Parameters.Length; i++) { ValidateMethodParameter(Parameters[i], ParameterValues[i]); } } #endregion #region 輔助方法 protected virtual void CheckInitialized() { if (Method == null) { throw new Exception("對象未初始化.請先調用初始化方法."); } } protected virtual bool IsValidationDisabled() { if (Method.IsDefined(typeof(EnableValidationAttribute), true)) { return false; } return ReflectionHelper.GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<DisableValidationAttribute>(Method) != null; } protected virtual bool HasSingleNullArgument() { return Parameters.Length == 1 && ParameterValues[0] == null; } /// <summary> /// 驗證給定值的給定參數。 /// </summary> /// <param name="parameterInfo">要驗證的方法的參數</param> /// <param name="parameterValue">要驗證的值</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; } SetDataAnnotationAttributeErrors(validatingObject); //Validate items of enumerable if (validatingObject is IEnumerable && !(validatingObject is IQueryable)) { foreach (var item in (validatingObject as IEnumerable)) { ValidateObjectRecursively(item, currentDepth + 1); } } if (validatingObject is IEnumerable) { return; } var validatingObjectType = validatingObject.GetType(); //不針對原始對象進行遞歸驗證 if (TypeHelper.IsPrimitiveExtendedIncludingNullable(validatingObjectType)) { return; } 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); } } /// <summary> /// 檢查DataAnnotations屬性的全部屬性。 /// </summary> protected virtual void SetDataAnnotationAttributeErrors(object validatingObject) { var properties = TypeDescriptor.GetProperties(validatingObject).Cast<PropertyDescriptor>(); foreach (var property in properties) { var validationAttributes = property.Attributes.OfType<ValidationAttribute>().ToArray(); if (validationAttributes.IsNullOrEmpty()) { continue; } var validationContext = new ValidationContext(validatingObject) { DisplayName = property.DisplayName, MemberName = property.Name }; foreach (var attribute in validationAttributes) { var result = attribute.GetValidationResult(property.GetValue(validatingObject), validationContext); if (result != null) { ValidationErrors.Add(result); } } } if (validatingObject is IValidatableObject) { var results = (validatingObject as IValidatableObject).Validate(new ValidationContext(validatingObject)); ValidationErrors.AddRange(results); } } #endregion }
使用攔截器得先註冊,框架中在BasicConventionalRegistrar註冊攔截器spa
public class BasicConventionalRegistrar : IConventionalDependencyRegistrar { public void RegisterAssembly(IConventionalRegistrationContext context) { //Windsor Interceptors context.IocManager.IocContainer.Register( Classes.FromAssembly(context.Assembly) .IncludeNonPublicTypes() .BasedOn<IInterceptor>() .If(type => !type.GetTypeInfo().IsGenericTypeDefinition) .WithService.Self() .LifestyleTransient() ); //註冊攔截器 //context.IocManager.IocContainer.Register( // Classes.FromThisAssembly() // .BasedOn<IInterceptor>() // .WithService.Self() // .LifestyleTransient()); //Transient context.IocManager.IocContainer.Register( Classes.FromAssembly(context.Assembly) .IncludeNonPublicTypes() .BasedOn<ITransientDependency>() .If(type => !type.GetTypeInfo().IsGenericTypeDefinition) .WithService.Self() .WithService.DefaultInterfaces() .LifestyleTransient() ); } }
在各個模塊啓動是調用便可code