/// <summary> /// Invokes the OnEntry method on all elements of the aspect chain. /// </summary> /// <param name="aspects">Aspect chain</param> /// <param name="args">Method arguments descriptor</param> /// <returns>Result of the execution</returns> // ReSharper disable ParameterTypeCanBeEnumerable.Local private static IMethodResultDescriptor OnEntry(AspectChain aspects, IMethodCallDescriptor args) // ReSharper restore ParameterTypeCanBeEnumerable.Local { try { if (aspects == null) { return(null); } IMethodResultDescriptor result = null; foreach (var aspect in aspects) { result = aspect.OnEntry(args, null); if (result != null) { break; } } return(result); } catch (Exception ex) { throw new AspectInfrastructureException( "Aspect infrastructure exception caught in OnEntry", ex); } }
/// <summary> /// Creates an intercepted object for the specified target using the provided aspect chain. /// </summary> /// <param name="serviceType">Type of service object</param> /// <param name="target">Target object to create an intercepted object for</param> /// <param name="aspects">Aspects to be used for the service object's method calls</param> /// <returns>Intercepted service object</returns> public static object GetInterceptedObject(Type serviceType, object target, AspectChain aspects) { if (serviceType == null) { throw new ArgumentNullException("serviceType"); } // --- Check the cache InterceptedTypeDescriptor interceptor; if (!s_Interceptors.TryGetValue(serviceType, out interceptor)) { lock (s_Interceptors) { // --- Validate again to prevent a parallel type creation if (!s_Interceptors.TryGetValue(serviceType, out interceptor)) { // --- Validate input parameters if (target == null) { throw new ArgumentNullException("target"); } if (!serviceType.IsInterface || !serviceType.IsInstanceOfType(target)) { throw new InvalidOperationException("Service type must be an interface" + " type and the target object must implement that interface."); } // --- No generics is accepted if (serviceType.IsGenericType || serviceType.GetMethods().Any(met => met.IsGenericMethod) || serviceType.GetInterfaces().Any(intf => intf.IsGenericType || intf.GetMethods().Any(met => met.IsGenericMethod))) { throw new InvalidOperationException( "Service type must not have generic parameters or methods."); } // --- We do not have any wrapper types for the specified service type // --- Generate the interceptor type and save it in the cache interceptor = new InterceptedTypeDescriptor { InterceptedType = serviceType, Methods = GetInterfaceMethods(serviceType) }; GenerateWrappedType(interceptor, serviceType); s_Interceptors[serviceType] = interceptor; } } } // --- Instantiate the wrapped type var wrappedInstance = Activator.CreateInstance( interceptor.WrapperType, new[] { target, aspects }); return(wrappedInstance); }
/// <summary> /// Checks whether two aspect chains are equal. /// </summary> /// <param name="other">The other aspect chain to check for equality</param> protected bool Equals(AspectChain other) { if (_aspects.Count != other._aspects.Count) { return(false); } return(!_aspects.Where((t, i) => !t.Equals(other._aspects[i]) && !ReferenceEquals(t, other._aspects[i])).Any()); }
/// <summary> /// Invokes the OnException method on all elements of the aspect chain. /// </summary> /// <param name="aspects">Aspect chain</param> /// <param name="args">Method arguments descriptor</param> /// <param name="ex">Exception instance</param> /// <returns>Result of the execution</returns> private static Exception OnException(AspectChain aspects, IMethodCallDescriptor args, Exception ex) { try { return(aspects == null ? ex : aspects.Reverse.Aggregate(ex, (current, aspect) => aspect.OnException(args, current))); } catch (Exception newEx) { throw new AspectInfrastructureException( "Aspect infrastructure exception caught in OnSuccess", newEx); } }
/// <summary> /// Invokes the OnSuccess method on all elements of the aspect chain. /// </summary> /// <param name="aspects">Aspect chain</param> /// <param name="args">Method arguments descriptor</param> /// <param name="result">Result of the method call</param> /// <returns>Result of the execution</returns> private static IMethodResultDescriptor OnSuccess(AspectChain aspects, IMethodCallDescriptor args, IMethodResultDescriptor result) { try { if (aspects != null) { foreach (var aspect in aspects.Reverse) { aspect.OnSuccess(args, result); } } return(result); } catch (Exception ex) { throw new AspectInfrastructureException( "Aspect infrastructure exception caught in OnSuccess", ex); } }
/// <summary> /// Invokes the OnExit method on all elements of the aspect chain. /// </summary> /// <param name="aspects">Aspect chain</param> /// <param name="args">Method arguments descriptor</param> /// <param name="result">Result of the method call</param> /// <returns>Result of the execution</returns> private static void OnExit(AspectChain aspects, IMethodCallDescriptor args, IMethodResultDescriptor result) { try { if (aspects == null) { return; } foreach (var aspect in aspects.Reverse) { aspect.OnExit(args, result); } } catch (Exception ex) { throw new AspectInfrastructureException( "Aspect infrastructure exception caught in OnExit", ex); } }
/// <summary> /// Creates an intercepted object for the specified target using the provided aspect chain. /// </summary> /// <typeparam name="TService">Type of service object</typeparam> /// <param name="target">Target object to create an intercepted object for</param> /// <param name="aspects">Aspects to be used for the service object's method calls</param> /// <returns>Intercepted service object</returns> public static TService GetInterceptedObject <TService>(TService target, AspectChain aspects) { return((TService)GetInterceptedObject(typeof(TService), target, aspects)); }
/// <summary> /// Executes the method call on the target object and wraps it into the execution of the /// specified object chain. /// </summary> /// <param name="target">Target object</param> /// <param name="arguments">Method call arguments</param> /// <param name="targetMethod"></param> /// <param name="aspects">Aspect chain to execute</param> /// <param name="methodInfo"></param> /// <returns>Result of the method execution</returns> public static IMethodResultDescriptor ExecuteWrappedCall <TService>(TService target, List <MethodArgument> arguments, MethodInfo methodInfo, Func <IMethodCallDescriptor, TService, IMethodResultDescriptor> targetMethod, AspectChain aspects) { // --- Use the aspects of the object, if that supports IMethodAspect if (aspects == null) { var typeAspects = GetAspects(methodInfo, target.GetType()); if (typeAspects.Count > 0) { aspects = new AspectChain(typeAspects); } } var targetAspect = target as IMethodAspect; if (targetAspect != null) { var aspectList = new List <IMethodAspect> { targetAspect }; if (aspects != null) { aspectList.AddRange(aspects); } aspects = new AspectChain(aspectList); } // --- Obtain the method descriptor var args = new MethodCallDescriptor(target, methodInfo, arguments); var onEntryResult = OnEntry(aspects, args); if (onEntryResult == null) { // --- Call original method body IMethodResultDescriptor result; try { result = targetMethod(args, target); } catch (Exception ex) { result = new MethodResultDescriptor(ex); } // --- Call OnExit OnExit(aspects, args, result); if (result.Exception == null) { onEntryResult = OnSuccess(aspects, args, result); } else { var newEx = OnException(aspects, args, result.Exception); if (newEx == null) { throw new AspectInfrastructureException("OnException returned null.", null); } throw newEx; } } return(onEntryResult); }