|
|
@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace ZeroLevel.Services.Reflection
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// For certain types of apps, such as web apps, <see cref="Assembly.GetEntryAssembly"/>
|
|
|
|
|
|
|
|
/// returns null. With the <see cref="EntryAssemblyAttribute"/>, we can designate
|
|
|
|
|
|
|
|
/// an assembly as the entry assembly by creating an instance of this attribute,
|
|
|
|
|
|
|
|
/// typically in the AssemblyInfo.cs file.
|
|
|
|
|
|
|
|
/// <example>
|
|
|
|
|
|
|
|
/// [assembly: EntryAssembly]
|
|
|
|
|
|
|
|
/// </example>
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
[AttributeUsage(AttributeTargets.Assembly)]
|
|
|
|
|
|
|
|
public sealed class EntryAssemblyAttribute : Attribute
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Lazily find the entry assembly.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
private static readonly Lazy<Assembly> EntryAssemblyLazy = new Lazy<Assembly>(GetEntryAssemblyLazily);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Gets the entry assembly.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
/// <returns>The entry assembly.</returns>
|
|
|
|
|
|
|
|
public static Assembly GetEntryAssembly()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return EntryAssemblyLazy.Value;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Invoked lazily to find the entry assembly. We want to cache this value as it may
|
|
|
|
|
|
|
|
/// be expensive to find.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
/// <returns>The entry assembly.</returns>
|
|
|
|
|
|
|
|
private static Assembly GetEntryAssemblyLazily()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return Assembly.GetEntryAssembly() ?? FindEntryAssemblyInCurrentAppDomain();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// Finds the entry assembly in the current app domain.
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
/// <returns>The entry assembly.</returns>
|
|
|
|
|
|
|
|
private static Assembly FindEntryAssemblyInCurrentAppDomain()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
|
|
|
|
|
|
|
var entryAssemblies = new List<Assembly>();
|
|
|
|
|
|
|
|
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<EntryAssemblyAttribute>().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();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|