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