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(); } } }