/// <summary> /// Called when an assembly is loaded in the current <see cref="AppDomain"/>. /// </summary> /// <param name="sender">The sender.</param> /// <param name="args">The <see cref="AssemblyLoadEventArgs" /> instance containing the event data.</param> private static void OnAssemblyLoaded(object sender, AssemblyLoadEventArgs args) { var assembly = args.LoadedAssembly; if (assembly.ReflectionOnly) { Log.Debug("Reflection '{0}' is loaded for reflection-only, cannot use this assembly", assembly.FullName); return; } lock (_lockObject) { var assemblyName = assembly.FullName; if (_loadedAssemblies.Contains(assemblyName)) { return; } InitializeTypes(false, assembly); var handler = AssemblyLoaded; if (handler != null) { var types = GetTypesOfAssembly(assembly); var eventArgs = new AssemblyLoadedEventArgs(assembly, types); handler(null, eventArgs); } _loadedAssemblies.Add(assemblyName); } }
private static void InitializeAssemblies(IEnumerable <Assembly> assemblies, bool force, bool allowMultithreadedInitialization = false) { // Important note: only allow explicit multithreaded initialization var listForLoadedEvent = new List <Tuple <Assembly, Type[]> >(); lock (_lockObject) { var assembliesToRetrieve = new List <Assembly>(); foreach (var assembly in assemblies) { var loadedAssemblyFullName = assembly.FullName; var containsLoadedAssembly = _loadedAssemblies.Contains(loadedAssemblyFullName); if (!force && containsLoadedAssembly) { continue; } if (!containsLoadedAssembly) { _loadedAssemblies.Add(loadedAssemblyFullName); } if (ShouldIgnoreAssembly(assembly)) { continue; } assembliesToRetrieve.Add(assembly); } var typesToAdd = GetAssemblyTypes(assembliesToRetrieve, allowMultithreadedInitialization); foreach (var assemblyWithTypes in typesToAdd) { foreach (var type in assemblyWithTypes.Value) { InitializeType(assemblyWithTypes.Key, type); } } #if NET || NETCORE || NETSTANDARD var lateLoadedAssemblies = new List <Assembly>(); lock (_threadSafeAssemblyQueue) { while (_threadSafeAssemblyQueue.Count > 0) { var assembly = _threadSafeAssemblyQueue.Dequeue(); lateLoadedAssemblies.Add(assembly); } } foreach (var lateLoadedAssembly in lateLoadedAssemblies) { var tuple = Tuple.Create(lateLoadedAssembly, GetTypesOfAssembly(lateLoadedAssembly)); listForLoadedEvent.Add(tuple); } #endif } // Calling out of lock statement, but still may happens that would be called inside of it var handler = AssemblyLoaded; if (handler != null) { foreach (var tuple in listForLoadedEvent) { var assembly = tuple.Item1; var types = tuple.Item2; var eventArgs = new AssemblyLoadedEventArgs(assembly, types); handler(null, eventArgs); } } }
private static void OnAssemblyLoaded(object sender, AssemblyLoadEventArgs args) { var assembly = args.LoadedAssembly; if (ShouldIgnoreAssembly(assembly)) { Log.Debug($"Reflection '{assembly.FullName}' is on the list to be ignored (for example, ReflectionOnly is true), cannot use this assembly"); return; } // Prevent deadlocks by checking whether this assembly might be loaded from a different thread: // 1) if (Monitor.TryEnter(_lockObject)) { var assemblyName = assembly.FullName; if (!_loadedAssemblies.Contains(assemblyName)) { // Fix for CTL-543 // General idea of fix - prevent to call GetTypes() method recursively. // When type load will fail CLR will try to localize message, and on // some OS's (i suspect on non english Windows and .NET) will try to load // satellite assembly with localization, Catel will get event before CLR // finishes handling process. Catel will try to initialize types. When another // type won't load CLR will detect that it still trying to handle previous // type load problem and will crash whole process. if (_isAlreadyInLoadingEvent) { // Will be proceed in finally block _onAssemblyLoadedDelayQueue.Enqueue(assembly); } else { try { _isAlreadyInLoadingEvent = true; InitializeTypes(assembly); } finally { while (_onAssemblyLoadedDelayQueue.Count > 0) { var delayedAssembly = _onAssemblyLoadedDelayQueue.Dequeue(); // Copy/pasted assembly processing behaviour, like types were processed without any delay InitializeTypes(delayedAssembly); } _isAlreadyInLoadingEvent = false; } } } Monitor.Exit(_lockObject); // Important to do outside of the lock var handler = AssemblyLoaded; if (handler != null) { var eventArgs = new AssemblyLoadedEventArgs(assembly, new Lazy <IEnumerable <Type> >(() => GetTypesOfAssembly(assembly))); handler(null, eventArgs); } } else { lock (_threadSafeAssemblyQueue) { _threadSafeAssemblyQueue.Enqueue(assembly); } // Note: AssemblyLoaded will be invoked later when the assembly // is actually loaded, fixed for https://github.com/Catel/Catel/issues/1120 } }
/// <summary> /// Called when an assembly is loaded in the current <see cref="AppDomain"/>. /// </summary> /// <param name="sender">The sender.</param> /// <param name="args">The <see cref="AssemblyLoadEventArgs" /> instance containing the event data.</param> private static void OnAssemblyLoaded(object sender, AssemblyLoadEventArgs args) { var assembly = args.LoadedAssembly; if (assembly.ReflectionOnly) { Log.Debug("Reflection '{0}' is loaded for reflection-only, cannot use this assembly", assembly.FullName); return; } InitializeTypes(false, assembly); var handler = AssemblyLoaded; if (handler != null) { var types = GetTypesOfAssembly(assembly); var eventArgs = new AssemblyLoadedEventArgs(assembly, types); handler(null, eventArgs); } }
/// <summary> /// Called when an assembly is loaded in the current <see cref="AppDomain"/>. /// </summary> /// <param name="sender">The sender.</param> /// <param name="args">The <see cref="AssemblyLoadEventArgs" /> instance containing the event data.</param> private static void OnAssemblyLoaded(object sender, AssemblyLoadEventArgs args) { var assembly = args.LoadedAssembly; if (ShouldIgnoreAssembly(assembly)) { Log.Debug("Reflection '{0}' is on the list to be ignored (for example, ReflectionOnly is true), cannot use this assembly", assembly.FullName); return; } // Prevent deadlocks by checking whether this assembly might be loaded from a different thread: // 1) if (Monitor.TryEnter(_lockObject)) { var assemblyName = assembly.FullName; if (!_loadedAssemblies.Contains(assemblyName)) { // Fix for CTL-543 // General idea of fix - prevent to call GetTypes() method recursively. // When type load will fail CLR will try to localize message, and on // some OS's (i suspect on non english Windows and .NET) will try to load // satellite assembly with localization, Catel will get event before CLR // finishes handling process. Catel will try to initialize types. When another // type won't load CLR will detect that it still trying to handle previous // type load problem and will crash whole process. if (_isAlreadyInLoadingEvent) { // Will be proceed in finally block _onAssemblyLoadedDelayQueue.Enqueue(assembly); } else { try { _isAlreadyInLoadingEvent = true; InitializeTypes(assembly); } finally { while (_onAssemblyLoadedDelayQueue.Count > 0) { var delayedAssembly = _onAssemblyLoadedDelayQueue.Dequeue(); // Copy/pasted assembly processing behaviour, like types were processed without any delay InitializeTypes(delayedAssembly); } _isAlreadyInLoadingEvent = false; } } } Monitor.Exit(_lockObject); } else { lock (_threadSafeAssemblyQueue) { _threadSafeAssemblyQueue.Enqueue(assembly); } } // Important to do outside of the lock var handler = AssemblyLoaded; if (handler != null) { var types = GetTypesOfAssembly(assembly); var eventArgs = new AssemblyLoadedEventArgs(assembly, types); handler(null, eventArgs); } }
/// <summary> /// Called when the <see cref="TypeCache.AssemblyLoaded"/> event occurs. /// </summary> /// <param name="sender">The sender.</param> /// <param name="e">The <see cref="AssemblyLoadedEventArgs"/> instance containing the event data.</param> private void OnAssemblyLoaded(object sender, AssemblyLoadedEventArgs e) { ClearCache(); }
/// <summary> /// Called when an assembly gets loaded. /// </summary> /// <param name="sender">The sender.</param> /// <param name="e">The <see cref="AssemblyLoadedEventArgs"/> instance containing the event data.</param> private static void OnAssemblyLoaded(object sender, AssemblyLoadedEventArgs e) { lock (_lockObject) { _serviceLocatorInitializers = null; } }