private void LoadAssemblies(string[] assembliesToLoad, IList <Assembly> loadedAssemblies) { foreach (string assemblyName in assembliesToLoad) { // Attempt to load assembly. Failures call logger and return null. Assembly a = AssemblyUtilities.LoadAssembly(assemblyName, this._logger); if (a != null) { loadedAssemblies.Add(a); } } }
/// <summary> /// Returns the set of <see cref="Assembly"/> instances that are referenced /// by the given <paramref name="assembly"/>. /// </summary> /// <remarks> /// The resulting collection will contain only those assemblies that loaded /// successfully, and it will not contain <c>null</c> values. Failed loads /// will be logged to the <paramref name="logger"/>. /// </remarks> /// <param name="assembly">The <see cref="Assembly"/> whose referenced assemblies are required.</param> /// <param name="logger">The optional logger to use to report known load failures.</param> /// <returns>The collection of referenced assemblies.</returns> public static IEnumerable <Assembly> GetReferencedAssemblies(Assembly assembly, Action <string> logger) { System.Diagnostics.Debug.Assert(assembly != null, "assembly cannot be null"); AssemblyName[] assemblyNames = (assembly == null) ? Array.Empty <AssemblyName>() : assembly.GetReferencedAssemblies(); List <Assembly> assemblies = new List <Assembly>(); foreach (AssemblyName assemblyName in assemblyNames) { Assembly a = AssemblyUtilities.LoadAssembly(assemblyName, logger); if (a != null) { assemblies.Add(a); } } return(assemblies); }
/// <summary> /// Gets the data objects for the <see cref="BusinessLogicContext"/> instances /// known by the current model. These data objects are marshalled across /// the AppDomain boundary by <see cref="ContextViewModel"/>. /// </summary> /// <returns>The set of data objects for the <see cref="BusinessLogicContext"/>s. /// This collection will always contain at least one element for the /// default empty context.</returns> public IContextData[] GetContextDataItems() { // This is lazily computed and cached. if (this._contexts == null) { List <Assembly> loadedAssemblies = new List <Assembly>(); this._contexts = new List <IBusinessLogicContext>(); // First load into this AppDomain all the assemblies we have been // asked to load. These 2 lists represent the assemblies of the candidate // types as well as all assemblies referenced by the candidate types' // assemblies. // Note, order is important here. Paths to reference assemblies were collected in the VS // app domain and could be static from when they were originally loaded. Assemblies // containing the context types were created dynamically and may be more recent. We // must load the assemblies containing the context types first since multiple assemblies // with the same name may not be loaded. this.LoadAssemblies(this.BusinessLogicData.AssemblyPaths, loadedAssemblies); this.LoadAssemblies(this.BusinessLogicData.ReferenceAssemblyPaths, loadedAssemblies); // Next, find the context types we were asked to use from those loaded assemblies List <Type> foundTypes = new List <Type>(); HashSet <string> contextTypeNames = new HashSet <string>(this.BusinessLogicData.ContextTypeNames); // We match the type from the other AppDomain to the corresponding one in our // AppDomain in one of two ways: // 1. Type.GetType() // 2. Scanning Assembly.GetExportedTypes // We do this because Type.GetType() is faster, but it will not work // for assemblies that cannot be loaded by the AssemblyName alone // (which occurs with binary references outside the project and in // class library projects when ASP.NET does not use the ASP.NET // temporary folders). // Pass 1: try to get the type directly foreach (string typeName in this.BusinessLogicData.ContextTypeNames) { Type t = Type.GetType(typeName, /* throwOnError */ false); if (t != null) { foundTypes.Add(t); contextTypeNames.Remove(t.AssemblyQualifiedName); } } // Pass 2: for any types not loaded above, locate them manually. foreach (Assembly a in loadedAssemblies) { if (contextTypeNames.Count > 0) { // Ask for all exported types. Use the safe version that logs issues // and unconditionally returns the collection (which could be empty). Type[] types = AssemblyUtilities.GetExportedTypes(a, this._logger).ToArray(); foreach (Type t in types) { // We remove each match from the candidate list and will take an early out // once that list is empty. if (contextTypeNames.Count > 0 && contextTypeNames.Contains(t.AssemblyQualifiedName)) { foundTypes.Add(t); contextTypeNames.Remove(t.AssemblyQualifiedName); } } } } // Add the default empty context at the top always this._contexts.Add(new BusinessLogicContext(null, Resources.BusinessLogic_Class_Empty_Class_Name)); // Create a BusinessLogicContext object for every type we matched in the new AppDomain foreach (Type t in foundTypes) { try { if (typeof(DataContext).IsAssignableFrom(t)) { this._contexts.Add(new LinqToSqlContext(t)); } else if (typeof(ObjectContext).IsAssignableFrom(t)) { this._contexts.Add(new LinqToEntitiesContext(t)); } else if (typeof(DbContext).IsAssignableFrom(t)) { this._contexts.Add(new LinqToEntitiesDbContext(t)); } else { this._logger(string.Format(CultureInfo.CurrentCulture, Resources.BusinessLogicClass_InvalidContextType, t.FullName)); } } catch (Exception ex) { this._logger(string.Format(CultureInfo.CurrentCulture, Resources.BusinessLogicClass_Failed_Load, t.FullName, ex.ToString())); } } // Report every type we did not match foreach (string typeName in contextTypeNames) { this._logger(string.Format(CultureInfo.CurrentCulture, Resources.BusinessLogicClass_Failed_Type_Load, typeName)); } } // just select out all the ContextData's. The other AppDomain does not get access // to the BusinessLogicContext objects, because we maintain type separation between // the AppDomains. return(this._contexts.Select <IBusinessLogicContext, IContextData>(blc => blc.ContextData).ToArray()); }