using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace ZeroLevel.Services.Reflection
{
///
/// For certain types of apps, such as web apps,
/// returns null. With the , we can designate
/// an assembly as the entry assembly by creating an instance of this attribute,
/// typically in the AssemblyInfo.cs file.
///
/// [assembly: EntryAssembly]
///
///
[AttributeUsage(AttributeTargets.Assembly)]
public sealed class EntryAssemblyAttribute : Attribute
{
///
/// Lazily find the entry assembly.
///
private static readonly Lazy EntryAssemblyLazy = new Lazy(GetEntryAssemblyLazily);
///
/// Gets the entry assembly.
///
/// The entry assembly.
public static Assembly GetEntryAssembly()
{
return EntryAssemblyLazy.Value;
}
///
/// Invoked lazily to find the entry assembly. We want to cache this value as it may
/// be expensive to find.
///
/// The entry assembly.
private static Assembly GetEntryAssemblyLazily()
{
return Assembly.GetEntryAssembly() ?? FindEntryAssemblyInCurrentAppDomain();
}
///
/// Finds the entry assembly in the current app domain.
///
/// The entry assembly.
private static Assembly FindEntryAssemblyInCurrentAppDomain()
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
var entryAssemblies = new List();
foreach (var assembly in assemblies)
{
// Note the usage of LINQ SingleOrDefault. The EntryAssemblyAttribute's AttrinuteUsage
// only allows it to occur once per assembly; declaring it more than once results in
// a compiler error.
var attribute =
assembly.GetCustomAttributes().OfType().SingleOrDefault();
if (attribute != null)
{
entryAssemblies.Add(assembly);
}
}
// Note that we use LINQ Single to ensure we found one and only one assembly with the
// EntryAssemblyAttribute. The EntryAssemblyAttribute should only be put on one assembly
// per application.
return entryAssemblies.SingleOrDefault();
}
}
}