1 // -----------------------------------------------------------------------
\r
2 // Copyright (c) Microsoft Corporation. All rights reserved.
\r
3 // -----------------------------------------------------------------------
\r
5 using System.Collections.Generic;
\r
6 using System.ComponentModel.Composition.Primitives;
\r
7 using System.ComponentModel.Composition.ReflectionModel;
\r
8 using System.Diagnostics;
\r
9 using System.Diagnostics.CodeAnalysis;
\r
10 using System.Globalization;
\r
13 using System.Reflection;
\r
14 using System.Security;
\r
15 using System.Threading;
\r
16 using Microsoft.Internal;
\r
18 namespace System.ComponentModel.Composition.Hosting
\r
21 /// An immutable ComposablePartCatalog created from a managed code assembly.
\r
24 /// This type is thread safe.
\r
26 [DebuggerTypeProxy(typeof(AssemblyCatalogDebuggerProxy))]
\r
27 public class AssemblyCatalog : ComposablePartCatalog, ICompositionElement
\r
29 private readonly object _thisLock = new object();
\r
30 private readonly ICompositionElement _definitionOrigin;
\r
31 private volatile Assembly _assembly = null;
\r
32 private volatile TypeCatalog _innerCatalog = null;
\r
33 private int _isDisposed = 0;
\r
38 /// Initializes a new instance of the <see cref="AssemblyCatalog"/> class
\r
39 /// with the specified code base.
\r
41 /// <param name="codeBase">
\r
42 /// A <see cref="String"/> containing the code base of the assembly containing the
\r
43 /// attributed <see cref="Type"/> objects to add to the <see cref="AssemblyCatalog"/>.
\r
45 /// <exception cref="ArgumentNullException">
\r
46 /// <paramref name="codeBase"/> is <see langword="null"/>.
\r
48 /// <exception cref="ArgumentException">
\r
49 /// <paramref name="codeBase"/> is a zero-length string, contains only white space,
\r
50 /// or contains one or more invalid characters as defined by <see cref="Path.InvalidPathChars"/>.
\r
52 /// <exception cref="PathTooLongException">
\r
53 /// The specified path, file name, or both exceed the system-defined maximum length.
\r
55 /// <exception cref="SecurityException">
\r
56 /// The caller does not have path discovery permission.
\r
58 /// <exception cref="FileNotFoundException">
\r
59 /// <paramref name="codeBase"/> is not found.
\r
61 /// <exception cref="FileLoadException ">
\r
62 /// <paramref name="codeBase"/> could not be loaded.
\r
66 /// <paramref name="codeBase"/> specified a directory.
\r
68 /// <exception cref="BadImageFormatException">
\r
69 /// <paramref name="codeBase"/> is not a valid assembly
\r
71 /// Version 2.0 or later of the common language runtime is currently loaded
\r
72 /// and <paramref name="codeBase"/> was compiled with a later version.
\r
75 /// The assembly referenced by <paramref langword="codeBase"/> is loaded into the Load context.
\r
77 public AssemblyCatalog(string codeBase)
\r
78 : this(codeBase, (ICompositionElement)null)
\r
82 internal AssemblyCatalog(string codeBase, ICompositionElement definitionOrigin)
\r
83 : this(LoadAssembly(codeBase), definitionOrigin)
\r
90 /// Initializes a new instance of the <see cref="AssemblyCatalog"/> class
\r
91 /// with the specified assembly.
\r
93 /// <param name="assembly">
\r
94 /// The <see cref="Assembly"/> containing the attributed <see cref="Type"/> objects to
\r
95 /// add to the <see cref="AssemblyCatalog"/>.
\r
97 /// <exception cref="ArgumentException">
\r
98 /// <paramref name="assembly"/> is <see langword="null"/>.
\r
102 /// <paramref name="assembly"/> was loaded in the reflection-only context.
\r
104 public AssemblyCatalog(Assembly assembly)
\r
105 : this(assembly, (ICompositionElement)null)
\r
109 internal AssemblyCatalog(Assembly assembly, ICompositionElement definitionOrigin)
\r
111 Requires.NotNull(assembly, "assembly");
\r
114 if (assembly.ReflectionOnly)
\r
116 throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.Argument_AssemblyReflectionOnly, "assembly"), "assembly");
\r
119 this._assembly = assembly;
\r
120 this._definitionOrigin = definitionOrigin ?? this;
\r
124 /// Gets the part definitions of the assembly catalog.
\r
127 /// A <see cref="IQueryable{T}"/> of <see cref="ComposablePartDefinition"/> objects of the
\r
128 /// <see cref="AssemblyCatalog"/>.
\r
130 /// <exception cref="ObjectDisposedException">
\r
131 /// The <see cref="AssemblyCatalog"/> has been disposed of.
\r
133 public override IQueryable<ComposablePartDefinition> Parts
\r
137 return this.InnerCatalog.Parts;
\r
142 /// Returns the export definitions that match the constraint defined by the specified definition.
\r
144 /// <param name="definition">
\r
145 /// The <see cref="ImportDefinition"/> that defines the conditions of the
\r
146 /// <see cref="ExportDefinition"/> objects to return.
\r
149 /// An <see cref="IEnumerable{T}"/> of <see cref="Tuple{T1, T2}"/> containing the
\r
150 /// <see cref="ExportDefinition"/> objects and their associated
\r
151 /// <see cref="ComposablePartDefinition"/> for objects that match the constraint defined
\r
152 /// by <paramref name="definition"/>.
\r
154 /// <exception cref="ArgumentNullException">
\r
155 /// <paramref name="definition"/> is <see langword="null"/>.
\r
157 /// <exception cref="ObjectDisposedException">
\r
158 /// The <see cref="ComposablePartCatalog"/> has been disposed of.
\r
161 /// <note type="inheritinfo">
\r
162 /// Overriders of this property should never return <see langword="null"/>, if no
\r
163 /// <see cref="ExportDefinition"/> match the conditions defined by
\r
164 /// <paramref name="definition"/>, return an empty <see cref="IEnumerable{T}"/>.
\r
167 public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition)
\r
169 return this.InnerCatalog.GetExports(definition);
\r
172 private TypeCatalog InnerCatalog
\r
176 this.ThrowIfDisposed();
\r
178 if (this._innerCatalog == null)
\r
180 lock (this._thisLock)
\r
182 if (this._innerCatalog == null)
\r
184 var catalog = new TypeCatalog(this._assembly.GetTypes(), _definitionOrigin);
\r
185 this._innerCatalog = catalog;
\r
189 return this._innerCatalog;
\r
194 /// Gets the assembly containing the attributed types contained within the assembly
\r
198 /// The <see cref="Assembly"/> containing the attributed <see cref="Type"/> objects
\r
199 /// contained within the <see cref="AssemblyCatalog"/>.
\r
201 public Assembly Assembly
\r
203 get { return this._assembly; }
\r
207 /// Gets the display name of the assembly catalog.
\r
210 /// A <see cref="String"/> containing a human-readable display name of the <see cref="AssemblyCatalog"/>.
\r
212 [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")]
\r
213 string ICompositionElement.DisplayName
\r
215 get { return this.GetDisplayName(); }
\r
219 /// Gets the composition element from which the assembly catalog originated.
\r
222 /// This property always returns <see langword="null"/>.
\r
224 [SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")]
\r
225 ICompositionElement ICompositionElement.Origin
\r
227 get { return null; }
\r
232 /// Returns a string representation of the assembly catalog.
\r
235 /// A <see cref="String"/> containing the string representation of the <see cref="AssemblyCatalog"/>.
\r
237 public override string ToString()
\r
239 return this.GetDisplayName();
\r
242 protected override void Dispose(bool disposing)
\r
246 if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0)
\r
250 if (this._innerCatalog != null)
\r
252 this._innerCatalog.Dispose();
\r
259 base.Dispose(disposing);
\r
263 private void ThrowIfDisposed()
\r
265 if (this._isDisposed == 1)
\r
267 throw ExceptionBuilder.CreateObjectDisposed(this);
\r
271 private string GetDisplayName()
\r
273 return string.Format(CultureInfo.CurrentCulture,
\r
274 "{0} (Assembly=\"{1}\")", // NOLOC
\r
276 this.Assembly.FullName);
\r
281 private static Assembly LoadAssembly(string codeBase)
\r
283 Requires.NotNullOrEmpty(codeBase, "codeBase");
\r
285 AssemblyName assemblyName;
\r
289 assemblyName = AssemblyName.GetAssemblyName(codeBase);
\r
291 catch (ArgumentException)
\r
293 assemblyName = new AssemblyName();
\r
294 assemblyName.CodeBase = codeBase;
\r
297 return Assembly.Load(assemblyName);
\r