Ejemplo n.º 1
0
        public override void OnExecute()
        {
            if (!(this.Builder.IsReferenced("Cauldron.Interception") || this.Builder.TypeExists("Cauldron.Interception.IMethodInterceptor")))
            {
                this.Log(LogTypes.Warning, arg: $"The assembly 'Cauldron.Interception' is not referenced or used in '{this.Builder.Name}'. Weaving will not continue.");
                return;
            }

            var versionAttribute = typeof(ModuleWeaver)
                                   .Assembly
                                   .GetCustomAttributes(typeof(System.Reflection.AssemblyFileVersionAttribute), true)
                                   .FirstOrDefault() as System.Reflection.AssemblyFileVersionAttribute;

            this.Log($"Cauldron Interception v" + versionAttribute.Version);

            var propertyInterceptingAttributes = this.Builder.FindAttributesByInterfaces(
                "Cauldron.Interception.IPropertyInterceptor",
                "Cauldron.Interception.IPropertyGetterInterceptor",
                "Cauldron.Interception.IPropertySetterInterceptor");

            var methodInterceptionAttributes = this.Builder.FindAttributesByInterfaces(
                "Cauldron.Interception.IMethodInterceptor");

            var constructorInterceptionHelperClass = new __IConstructorInterceptor(this.Builder);
            var constructorInterceptionAttributes  = this.Builder.FindAttributesByInterfaces(constructorInterceptionHelperClass.Type.Fullname);

            this.ImplementAnonymousTypeInterface(this.Builder);
            this.ImplementTimedCache(this.Builder);
            // this.ImplementMethodCache(this.Builder);
            this.ImplementBamlInitializer(this.Builder);
            this.ImplementTypeWidePropertyInterception(this.Builder, propertyInterceptingAttributes);
            this.ImplementTypeWideMethodInterception(this.Builder, methodInterceptionAttributes);
            // These should be done last, because they replace methods
            this.InterceptConstructors(this.Builder, constructorInterceptionAttributes);
            this.InterceptFields(this.Builder, propertyInterceptingAttributes);
            this.InterceptMethods(this.Builder, methodInterceptionAttributes);
            this.InterceptProperties(this.Builder, propertyInterceptingAttributes);

            this.CreateFactoryCache(this.Builder);

            if (this.Builder.TypeExists("Cauldron.XAML.ApplicationBase") && this.Builder.IsReferenced("PropertyChanged"))
            {
                this.ImplementPropertyChangedEvent(this.Builder);
            }

            if (this.Builder.TypeExists("Cauldron.XAML.Validation.ValidatorGroup"))
            {
                this.AddValidatorInits(this.Builder);
            }

            // Checks
            this.CheckAsyncMthodsNomenclature(this.Builder);
        }
        private void InterceptConstructors(Builder builder, IEnumerable <BuilderType> attributes)
        {
            if (!attributes.Any())
            {
                return;
            }

            using (new StopwatchLog(this, "constructor"))
            {
                var iConstructorInterceptor = new __IConstructorInterceptor();
                var syncRoot  = new __ISyncRoot();
                var exception = new __Exception();

                var constructors = builder
                                   .FindMethodsByAttributes(attributes)
                                   .Where(x => !x.Method.OriginType.IsInterface)
                                   .GroupBy(x => new MethodKey(x.Method, null))
                                   .Select(x => new MethodBuilderInfo <MethodBuilderInfoItem <__IConstructorInterceptor> >(x.Key, x.Select(y => new MethodBuilderInfoItem <__IConstructorInterceptor>(y, iConstructorInterceptor))))
                                   .ToArray();

                foreach (var constructor in constructors)
                {
                    this.Log($"Implementing constructors in method {constructor.Key.Method}");

                    if (constructor.Item == null || constructor.Item.Length == 0)
                    {
                        continue;
                    }

                    var targetedConstrutor = constructor.Key.Method;

                    if (constructor.RequiresSyncRootField)
                    {
                        this.Log(LogTypes.Warning, targetedConstrutor, $"An interceptor applied to the constructor has implemented ISyncRoot. This is not supported. The interceptor may not work correctly.");
                    }

                    Crumb parametersArray = null;
                    var   localVariables  = new LocalVariable[constructor.Item.Length];
                    var   interceptorInit = new Action <ICode, bool>((contextCoder, isBeforeInit) =>
                    {
                        parametersArray = contextCoder.GetParametersArray();

                        for (int i = 0; i < constructor.Item.Length; i++)
                        {
                            var item          = constructor.Item[i];
                            localVariables[i] = contextCoder.CreateVariable(item.Attribute.Attribute.Type);

                            contextCoder.Assign(localVariables[i]).NewObj(item.Attribute);

                            ImplementAssignMethodAttribute(builder, item.AssignMethodAttributeInfos, localVariables[i], contextCoder, isBeforeInit);

                            contextCoder.Load(localVariables[i]).As(item.Interface.ToBuilderType)
                            .Call(item.Interface.OnBeforeInitialization, targetedConstrutor.OriginType, targetedConstrutor, parametersArray);

                            item.Attribute.Remove();
                        }
                    });

                    if (targetedConstrutor.IsCtor)
                    {
                        targetedConstrutor.NewCode()
                        .Context(x => interceptorInit(x, true))
                        .Insert(InsertionPosition.CtorBeforeInit);
                    }

                    targetedConstrutor.NewCode()
                    .Context(x =>
                    {
                        if (targetedConstrutor.IsCCtor)
                        {
                            interceptorInit(x, false);
                        }
                    })
                    .Try(x =>
                    {
                        for (int i = 0; i < constructor.Item.Length; i++)
                        {
                            var item = constructor.Item[i];
                            x.Load(localVariables[i]).As(item.Interface.ToBuilderType)
                            .Call(item.Interface.OnEnter, targetedConstrutor.OriginType, Crumb.This, targetedConstrutor, parametersArray);
                        }

                        x.OriginalBody();
                    })
                    .Catch(exception.ToBuilderType, x =>
                    {
                        if (constructor.Key.AsyncMethod == null)
                        {
                            for (int i = 0; i < constructor.Item.Length; i++)
                            {
                                x.Load(localVariables[i]).As(constructor.Item[i].Interface.ToBuilderType).Call(constructor.Item[i].Interface.OnException, x.Exception);
                            }
                        }

                        x.Rethrow();
                    })
                    .Finally(x =>
                    {
                        for (int i = 0; i < constructor.Item.Length; i++)
                        {
                            x.Load(localVariables[i]).As(constructor.Item[i].Interface.ToBuilderType).Call(constructor.Item[i].Interface.OnExit);
                        }
                    })
                    .EndTry()
                    .Return()
                    .Replace();
                }
            }
        }