// -----------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// -----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Primitives;
using System.ComponentModel.Composition.ReflectionModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security;
using System.Threading;
using Microsoft.Internal;
namespace System.ComponentModel.Composition.Hosting
{
///
/// An immutable ComposablePartCatalog created from a managed code assembly.
///
///
/// This type is thread safe.
///
[DebuggerTypeProxy(typeof(AssemblyCatalogDebuggerProxy))]
public class AssemblyCatalog : ComposablePartCatalog, ICompositionElement
{
private readonly object _thisLock = new object();
private readonly ICompositionElement _definitionOrigin;
private volatile Assembly _assembly = null;
private volatile TypeCatalog _innerCatalog = null;
private int _isDisposed = 0;
#if !SILVERLIGHT
///
/// Initializes a new instance of the class
/// with the specified code base.
///
///
/// A containing the code base of the assembly containing the
/// attributed objects to add to the .
///
///
/// is .
///
///
/// is a zero-length string, contains only white space,
/// or contains one or more invalid characters as defined by .
///
///
/// The specified path, file name, or both exceed the system-defined maximum length.
///
///
/// The caller does not have path discovery permission.
///
///
/// is not found.
///
///
/// could not be loaded.
///
/// -or-
///
/// specified a directory.
///
///
/// is not a valid assembly
/// -or-
/// Version 2.0 or later of the common language runtime is currently loaded
/// and was compiled with a later version.
///
///
/// The assembly referenced by is loaded into the Load context.
///
public AssemblyCatalog(string codeBase)
: this(codeBase, (ICompositionElement)null)
{
}
internal AssemblyCatalog(string codeBase, ICompositionElement definitionOrigin)
: this(LoadAssembly(codeBase), definitionOrigin)
{
}
#endif
///
/// Initializes a new instance of the class
/// with the specified assembly.
///
///
/// The containing the attributed objects to
/// add to the .
///
///
/// is .
///
/// -or-
///
/// was loaded in the reflection-only context.
///
public AssemblyCatalog(Assembly assembly)
: this(assembly, (ICompositionElement)null)
{
}
internal AssemblyCatalog(Assembly assembly, ICompositionElement definitionOrigin)
{
Requires.NotNull(assembly, "assembly");
#if !SILVERLIGHT
if (assembly.ReflectionOnly)
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Strings.Argument_AssemblyReflectionOnly, "assembly"), "assembly");
}
#endif
this._assembly = assembly;
this._definitionOrigin = definitionOrigin ?? this;
}
///
/// Gets the part definitions of the assembly catalog.
///
///
/// A of objects of the
/// .
///
///
/// The has been disposed of.
///
public override IQueryable Parts
{
get
{
return this.InnerCatalog.Parts;
}
}
///
/// Returns the export definitions that match the constraint defined by the specified definition.
///
///
/// The that defines the conditions of the
/// objects to return.
///
///
/// An of containing the
/// objects and their associated
/// for objects that match the constraint defined
/// by .
///
///
/// is .
///
///
/// The has been disposed of.
///
///
///
/// Overriders of this property should never return , if no
/// match the conditions defined by
/// , return an empty .
///
///
public override IEnumerable> GetExports(ImportDefinition definition)
{
return this.InnerCatalog.GetExports(definition);
}
private TypeCatalog InnerCatalog
{
get
{
this.ThrowIfDisposed();
if (this._innerCatalog == null)
{
lock (this._thisLock)
{
if (this._innerCatalog == null)
{
var catalog = new TypeCatalog(this._assembly.GetTypes(), _definitionOrigin);
this._innerCatalog = catalog;
}
}
}
return this._innerCatalog;
}
}
///
/// Gets the assembly containing the attributed types contained within the assembly
/// catalog.
///
///
/// The containing the attributed objects
/// contained within the .
///
public Assembly Assembly
{
get { return this._assembly; }
}
///
/// Gets the display name of the assembly catalog.
///
///
/// A containing a human-readable display name of the .
///
string ICompositionElement.DisplayName
{
get { return this.GetDisplayName(); }
}
///
/// Gets the composition element from which the assembly catalog originated.
///
///
/// This property always returns .
///
ICompositionElement ICompositionElement.Origin
{
get { return null; }
}
///
/// Returns a string representation of the assembly catalog.
///
///
/// A containing the string representation of the .
///
public override string ToString()
{
return this.GetDisplayName();
}
protected override void Dispose(bool disposing)
{
if (Interlocked.CompareExchange(ref this._isDisposed, 1, 0) == 0)
{
try
{
if (disposing)
{
if (this._innerCatalog != null)
{
this._innerCatalog.Dispose();
}
}
}
finally
{
base.Dispose(disposing);
}
}
}
private void ThrowIfDisposed()
{
if (this._isDisposed == 1)
{
throw ExceptionBuilder.CreateObjectDisposed(this);
}
}
private string GetDisplayName()
{
return string.Format(CultureInfo.CurrentCulture,
"{0} (Assembly=\"{1}\")", // NOLOC
GetType().Name,
this.Assembly.FullName);
}
#if !SILVERLIGHT
private static Assembly LoadAssembly(string codeBase)
{
Requires.NotNullOrEmpty(codeBase, "codeBase");
AssemblyName assemblyName;
try
{
assemblyName = AssemblyName.GetAssemblyName(codeBase);
}
catch (ArgumentException)
{
assemblyName = new AssemblyName();
assemblyName.CodeBase = codeBase;
}
return Assembly.Load(assemblyName);
}
#endif
}
}