Esempio n. 1
0
 /// <summary>
 /// Implements advice logic.
 ///             Usually, advice must invoke context.Proceed()
 /// </summary>
 /// <param name="context">The parameter advice context.</param>
 void IParameterAdvice.Advise(ParameterAdviceContext context)
 {
     if (context.Value == null && !context.IsOut)
     {
         Logging.DebugMessage("Parameter {0} is null on {1}", context.TargetParameter.Name, context.TargetType.FullName);
         throw new ArgumentNullException(context.TargetParameter.Name, string.Format("Parameter '{0}' in method {2} is null on '{1}'", context.TargetParameter.Name, context.TargetType.FullName, context.TargetParameter.Member.Name));
     }
     context.Proceed();
 }
Esempio n. 2
0
 /// <summary>
 /// Implements advice logic.
 ///             Usually, advice must invoke context.Proceed()
 /// </summary>
 /// <param name="context">The parameter advice context.</param>
 void IParameterAdvice.Advise(ParameterAdviceContext context)
 {
     if (context.Value == null && !context.IsOut)
     {
         Logging.DebugMessage("Parameter {0} is null on {1}", context.TargetParameter.Name, context.TargetType.FullName);
         throw new ArgumentNullException(context.TargetParameter.Name, string.Format("Parameter '{0}' in method {2} is null on '{1}'", context.TargetParameter.Name, context.TargetType.FullName, context.TargetParameter.Member.Name));
     }
     context.Proceed();
 }
Esempio n. 3
0
 public void Advise(ParameterAdviceContext context)
 {
     if (context.IsIn)
     {
         if (context.ParameterType == typeof(int))
             context.SetValue(context.GetValue<int>() + 1);
         if (context.ParameterType == typeof(string))
             context.SetValue(context.GetValue<string>() + "there");
     }
     context.Proceed();
     if (context.IsOut && !context.IsIn)
         context.SetValue(context.GetValue<int>() * 2);
 }
Esempio n. 4
0
 public void Advise(ParameterAdviceContext context)
 {
     if (context.IsIn)
     {
         if (context.ParameterType == typeof(int))
         {
             context.SetValue(context.GetValue <int>() + 1);
         }
         if (context.ParameterType == typeof(string))
         {
             context.SetValue(context.GetValue <string>() + "there");
         }
     }
     context.Proceed();
     if (context.IsOut && !context.IsIn)
     {
         context.SetValue(context.GetValue <int>() * 2);
     }
 }
Esempio n. 5
0
        private static AdviceContext CreateAdviceContext(AdviceValues adviceValues, AspectInfo aspectInfo)
        {
            AdviceContext adviceContext = new InnerMethodContext(adviceValues, aspectInfo.PointcutMethod, aspectInfo.PointcutMethodDelegate);

            for (var adviceIndex = aspectInfo.Advices.Count - 1; adviceIndex >= 0; adviceIndex--)
            {
                var advice = aspectInfo.Advices[adviceIndex];
                // aspects are processed from highest to lowest level, so they are linked here in the opposite order
                // 3. as parameter
                if (advice.ParameterAdvice != null && advice.ParameterIndex.HasValue)
                {
                    var parameterIndex = advice.ParameterIndex.Value;
                    var parameterInfo  = GetParameterInfo(aspectInfo.AdvisedMethod, parameterIndex);
                    adviceContext = new ParameterAdviceContext(advice.ParameterAdvice, parameterInfo, parameterIndex, adviceValues, adviceContext);
                }
                // 2. as method
                if (advice.MethodAdvice != null)
                {
                    adviceContext = new MethodAdviceContext(advice.MethodAdvice, aspectInfo.AdvisedMethod, adviceValues, adviceContext);
                }
                // 2b. as async method
                if (advice.AsyncMethodAdvice != null)
                {
                    adviceContext = new MethodAsyncAdviceContext(advice.AsyncMethodAdvice, aspectInfo.AdvisedMethod, adviceValues, adviceContext);
                }
                // 1. as property
                if (advice.PropertyAdvice != null && aspectInfo.PointcutProperty != null)
                {
                    adviceContext = new PropertyAdviceContext(advice.PropertyAdvice, aspectInfo.PointcutProperty, aspectInfo.IsPointcutPropertySetter, adviceValues, adviceContext);
                }
                // 1b. as event
                if (advice.EventAdvice != null && aspectInfo.PointcutEvent != null)
                {
                    adviceContext = new EventAdviceContext(advice.EventAdvice, aspectInfo.PointcutEvent, aspectInfo.IsPointcutEventAdder, adviceValues, adviceContext);
                }
            }

            return(adviceContext);
        }
Esempio n. 6
0
        /// <summary>
        /// Runs a method interception.
        /// We use a static method here, if one day we want to reuse Invocations or change mecanism,
        /// it will be easier from C# code
        /// </summary>
        /// <param name="target">The target.</param>
        /// <param name="parameters">The parameters.</param>
        /// <param name="methodHandle">The method handle.</param>
        /// <param name="innerMethodHandle">The inner method handle.</param>
        /// <param name="delegatableMethodHandle">The delegatable method handle.</param>
        /// <param name="typeHandle">The type handle.</param>
        /// <param name="abstractedTarget">if set to <c>true</c> [abstracted target].</param>
        /// <param name="genericArguments">The generic arguments (to static type and/or method) in a single array.</param>
        /// <returns></returns>
        // ReSharper disable once UnusedMember.Global
        // ReSharper disable once UnusedMethodReturnValue.Global
        public static object ProceedAdvice2(object target, object[] parameters, RuntimeMethodHandle methodHandle, RuntimeMethodHandle innerMethodHandle,
                                            RuntimeMethodHandle delegatableMethodHandle, RuntimeTypeHandle typeHandle, bool abstractedTarget, Type[] genericArguments)
        {
            var aspectInfo = GetAspectInfo(methodHandle, innerMethodHandle, delegatableMethodHandle, typeHandle, abstractedTarget, genericArguments);

            // this is the case with auto implemented interface
            if (target is AdvisedInterface advisedInterface)
            {
                aspectInfo = aspectInfo.AddAdvice(new AdviceInfo(advisedInterface.Advice));
            }

            foreach (var advice in aspectInfo.Advices)
            {
                InjectIntroducedFields(advice, aspectInfo.AdvisedMethod.DeclaringType);
            }

            // from here, we build an advice chain, with at least one final advice: the one who calls the method
            var adviceValues = new AdviceValues(target, aspectInfo.AdvisedMethod.DeclaringType, parameters);
            // at least there is one context
            AdviceContext adviceContext = new InnerMethodContext(adviceValues, aspectInfo.PointcutMethod, aspectInfo.PointcutMethodDelegate);

            for (var adviceIndex = aspectInfo.Advices.Count - 1; adviceIndex >= 0; adviceIndex--)
            {
                var advice = aspectInfo.Advices[adviceIndex];
                // aspects are processed from highest to lowest level, so they are linked here in the opposite order
                // 3. as parameter
                if (advice.ParameterAdvice != null && advice.ParameterIndex.HasValue)
                {
                    var parameterIndex = advice.ParameterIndex.Value;
                    var parameterInfo  = GetParameterInfo(aspectInfo.AdvisedMethod, parameterIndex);
                    adviceContext = new ParameterAdviceContext(advice.ParameterAdvice, parameterInfo, parameterIndex, adviceValues, adviceContext);
                }
                // 2. as method
                if (advice.MethodAdvice != null)
                {
                    adviceContext = new MethodAdviceContext(advice.MethodAdvice, aspectInfo.AdvisedMethod, adviceValues, adviceContext);
                }
                // 2b. as async method
                if (advice.AsyncMethodAdvice != null)
                {
                    adviceContext = new MethodAsyncAdviceContext(advice.AsyncMethodAdvice, aspectInfo.AdvisedMethod, adviceValues, adviceContext);
                }
                // 1. as property
                if (advice.PropertyAdvice != null && aspectInfo.PointcutProperty != null)
                {
                    adviceContext = new PropertyAdviceContext(advice.PropertyAdvice, aspectInfo.PointcutProperty, aspectInfo.IsPointcutPropertySetter, adviceValues, adviceContext);
                }
                // 1b. as event
                if (advice.EventAdvice != null && aspectInfo.PointcutEvent != null)
                {
                    adviceContext = new EventAdviceContext(advice.EventAdvice, aspectInfo.PointcutEvent, aspectInfo.IsPointcutEventAdder, adviceValues, adviceContext);
                }
            }

            // if the method is no task, then we return immediately
            // (and the adviceTask is completed)
            var adviceTask = adviceContext.Invoke();

            var advisedMethodInfo = aspectInfo.AdvisedMethod as MethodInfo;
            var returnType        = advisedMethodInfo?.ReturnType;

            // no Task means aspect was sync, so everything already ended
            // or it may also been an async void, meaning that we don't care about it
            if (adviceTask == null || returnType == null || !typeof(Task).GetAssignmentReader().IsAssignableFrom(returnType))
            {
                adviceTask?.Wait();
                return(adviceValues.ReturnValue);
            }

            // otherwise, see if it is a Task or Task<>

            // Task is simple too: the advised method is a subtask,
            // so the advice is completed after the method is completed too
            if (returnType == typeof(Task))
            {
                return(adviceTask);
            }

            // only Task<> left here
            var taskType = returnType.GetTaskType();

            // a reflection equivalent of ContinueWith<TNewResult>, but this TNewResult, under taskType is known only at run-time
            return(adviceTask.ContinueWith(t => GetResult(t, adviceValues), taskType));
        }
Esempio n. 7
0
        /// <summary>
        /// Runs a method interception.
        /// We use a static method here, if one day we want to reuse Invocations or change mecanism,
        /// it will be easier from C# code
        /// </summary>
        /// <param name="target">The target.</param>
        /// <param name="parameters">The parameters.</param>
        /// <param name="methodBase">The raw method base.</param>
        /// <param name="innerMethod">The inner method.</param>
        /// <param name="abstractedTarget">if set to <c>true</c> [abstracted target].</param>
        /// <param name="genericArguments">The generic arguments (to static type and/or method) in a single array.</param>
        /// <returns></returns>
        // ReSharper disable once UnusedMember.Global
        // ReSharper disable once UnusedMethodReturnValue.Global
        public static object ProceedAdvice(object target, object[] parameters, MethodBase methodBase, MethodBase innerMethod, bool abstractedTarget, Type[] genericArguments)
        {
            var aspectInfo = GetAspectInfo(methodBase, innerMethod, abstractedTarget, genericArguments);

            // this is the case with auto implemented interface
            var advisedInterface = target as AdvisedInterface;

            if (advisedInterface != null)
            {
                aspectInfo = aspectInfo.AddAdvice(new AdviceInfo(advisedInterface.Advice));
            }

            foreach (var advice in aspectInfo.Advices.Select(a => a.Advice).Distinct())
            {
                InjectIntroducedFields(advice, methodBase.DeclaringType);
            }

            // from here, we build an advice chain, with at least one final advice: the one who calls the method
            var adviceValues = new AdviceValues(target, aspectInfo.AdvisedMethod.DeclaringType, parameters);
            // at least there is one context
            AdviceContext adviceContext = new InnerMethodContext(adviceValues, aspectInfo.PointcutMethod);

            foreach (var advice in aspectInfo.Advices.Reverse())
            {
                // aspects are processed from highest to lowest level, so they are linked here in the opposite order
                // 3. as parameter
                if (advice.ParameterAdvice != null && advice.ParameterIndex.HasValue)
                {
                    var parameterIndex = advice.ParameterIndex.Value;
                    var parameterInfo  = GetParameterInfo(aspectInfo.AdvisedMethod, parameterIndex);
                    adviceContext = new ParameterAdviceContext(advice.ParameterAdvice, parameterInfo, parameterIndex, adviceValues, adviceContext);
                }
                // 2. as method
                if (advice.MethodAdvice != null)
                {
                    adviceContext = new MethodAdviceContext(advice.MethodAdvice, aspectInfo.AdvisedMethod, adviceValues, adviceContext);
                }
                // 2b. as async method
                if (advice.AsyncMethodAdvice != null)
                {
                    adviceContext = new MethodAsyncAdviceContext(advice.AsyncMethodAdvice, aspectInfo.AdvisedMethod, adviceValues, adviceContext);
                }
                // 1. as property
                if (advice.PropertyAdvice != null && aspectInfo.PointcutProperty != null)
                {
                    adviceContext = new PropertyAdviceContext(advice.PropertyAdvice, aspectInfo.PointcutProperty, aspectInfo.IsPointcutPropertySetter, adviceValues, adviceContext);
                }
            }

            // if the method is no task, then we return immediately
            // (and the adviceTask is completed)
            var adviceTask = adviceContext.Invoke();

            var advisedMethodInfo = aspectInfo.AdvisedMethod as MethodInfo;
            var returnType        = advisedMethodInfo?.ReturnType;

            // no Task means aspect was sync, so everything already ended
            // TODO: this is actually not true, since an async method can be void :frown:
            if (adviceTask == null || returnType == null || !typeof(Task).IsAssignableFrom(returnType))
            {
                adviceTask?.Wait();
                return(adviceValues.ReturnValue);
            }

            // otherwise, see if it is a Task or Task<>

            // Task is simple too: the advised method is a subtask,
            // so the advice is completed after the method is completed too
            if (returnType == typeof(Task))
            {
                return(adviceTask);
            }

            // only Task<> left here
            // we need to create a new source and mark it as complete once the advice has completed
            var adviceTaskSource = TaskCompletionSource.Create(returnType.GetTaskType());

            adviceTask.ContinueWith(t => ContinueTask(t, adviceTaskSource, adviceValues));
            return(adviceTaskSource.Task);
        }