Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.IO;
- using System.Linq;
- using System.Reflection;
- namespace Demo
- {
- /// <summary>
- /// This class defines the static registration behavior of this assembly.
- /// </summary>
- /// <remarks>
- /// The implementation of the module initialization mechanism relies on
- /// an single internal or public class, contained in any namespace, named
- /// "ModuleInitializer". It is vitally important that the signature of this
- /// class be exactly: internal|public static class ModuleInitializer
- /// </remarks>
- internal static class ModuleInitializer
- {
- private static void RegisterTypes()
- {
- // TODO: Delete the example registrations below, and add registrations for your library.
- // You can register a specific type.
- Registrar.Register<IFoo>(foo => Foo.Current = foo);
- // Or you can register a specific type along with a factory that creates instances of that type.
- Registrar.Register<IBar, IBarFactory>(bar => Bar.Current = bar, factory => factory.GetBar());
- }
- #region Extension Points (TODO: Customize as necessary)
- // TODO: Implement a mechanism for reversing the default TFactoryType-over-TTargetType priority.
- internal static ProxyRegisterTypeAttribute GetProxyRegisterTypeAttribute(Type type)
- {
- // NOTE: To disable this extension point, return null.
- // TODO: Replace 'ExportAttribute' with your attribute type.
- var attribute = (ExportAttribute)Attribute.GetCustomAttribute(type, typeof(ExportAttribute));
- return
- attribute == null
- ? null
- : new ProxyRegisterTypeAttribute(
- // TODO: Replace 'attribute.HighPriority ? 1 : -2' with however you get a priority value.
- () => attribute.HighPriority ? 1 : -2,
- // TODO: Replace 'true' with however you get an enabled value.
- () => true);
- }
- #endregion
- #region Don't change anything in this region
- internal interface IRegisterTypeAttribute
- {
- int Priority { get; }
- bool Enabled { get; }
- }
- /// <summary>
- /// This is the entry point of an assembly upon being loaded for the first time.
- /// It is not intended to be used directly.
- /// </summary>
- /// <remarks>
- /// The implementation of the module initialization mechanism relies on
- /// a void method named "Run" with no parameters. It is vitally important
- /// that the signature be exactly: internal static void Run()
- /// </remarks>
- internal static void Run()
- {
- RegisterTypes();
- Registrar.TearDown();
- }
- internal class ProxyRegisterTypeAttribute : IRegisterTypeAttribute
- {
- private readonly Func<int> _getPriorityFunc;
- private readonly Func<bool> _getEnabledFunc;
- public ProxyRegisterTypeAttribute(
- Func<int> getPriorityFunc,
- Func<bool> getEnabledFunc)
- {
- _getPriorityFunc = getPriorityFunc;
- _getEnabledFunc = getEnabledFunc;
- }
- public int Priority { get { return _getPriorityFunc(); } }
- public bool Enabled { get { return _getEnabledFunc(); } }
- }
- #endregion
- }
- #region Registrar
- internal static class Registrar
- {
- private const string _eventLogSource = ".NET Runtime";
- private const string _eventLogName = "Application";
- private static Lazy<ICollection<Type>> _candidateTypes;
- static Registrar()
- {
- CheckEventLogSource();
- _candidateTypes = new Lazy<ICollection<Type>>(GetCandidateTypes);
- }
- public static void Register<TTargetType>(Action<TTargetType> registerAction)
- where TTargetType : class
- {
- var prioritizedGroupsOfCandidateTypes =
- GetPrioritizedGroupsOfCandidateTypes(
- GetCandidateTypeNames<TTargetType>());
- foreach (var candidateTypes in prioritizedGroupsOfCandidateTypes)
- {
- var candidateType = ChooseCandidateType(candidateTypes);
- if (candidateType == null)
- {
- Warn(candidateTypes, typeof(TTargetType).FullName);
- }
- else
- {
- var instance = GetTargetInstance<TTargetType>(candidateType);
- if (instance != null)
- {
- registerAction(instance);
- return;
- }
- }
- }
- }
- public static void Register<TTargetType, TFactoryType>(
- Action<TTargetType> registerAction,
- Func<TFactoryType, TTargetType> createTargetFunc)
- where TTargetType : class
- where TFactoryType : class
- {
- var prioritizedGroupsOfCandidateTypes =
- GetPrioritizedGroupsOfCandidateTypes(
- GetCandidateTypeNames<TTargetType>()
- .Concat(GetCandidateTypeNames<TFactoryType>()));
- foreach (var candidateTypes in prioritizedGroupsOfCandidateTypes)
- {
- var candidateType = ChooseCandidateType<TTargetType, TFactoryType>(candidateTypes);
- if (candidateType == null)
- {
- Warn(
- candidateTypes,
- string.Format(
- "either {0} or {1}",
- typeof(TFactoryType).FullName,
- typeof(TTargetType).FullName));
- }
- else
- {
- var instance = GetTargetInstance(candidateType, createTargetFunc);
- if (instance != null)
- {
- registerAction(instance);
- return;
- }
- }
- }
- }
- public static void TearDown()
- {
- _candidateTypes = null;
- }
- private static TTargetType GetTargetInstance<TTargetType>(Type candidateType)
- where TTargetType : class
- {
- try
- {
- var instance = Instantiate(candidateType);
- var target = instance as TTargetType;
- if (target != null)
- {
- return target;
- }
- return null;
- }
- catch
- {
- return null;
- }
- }
- private static TTargetType GetTargetInstance<TTargetType, TFactoryType>(
- Type candidateType,
- Func<TFactoryType, TTargetType> createTargetFunc)
- where TTargetType : class
- where TFactoryType : class
- {
- try
- {
- var instance = Instantiate(candidateType);
- var factory = instance as TFactoryType;
- if (factory != null)
- {
- return createTargetFunc(factory);
- }
- var target = instance as TTargetType;
- if (target != null)
- {
- return target;
- }
- return null;
- }
- catch
- {
- return null;
- }
- }
- private static object Instantiate(Type candidateType)
- {
- if (candidateType.GetConstructor(Type.EmptyTypes) != null)
- {
- return Activator.CreateInstance(candidateType);
- }
- var ctor =
- candidateType.GetConstructors()
- .OrderByDescending(c => c.GetParameters().Length)
- .First(c => c.GetParameters().All(HasDefaultValue));
- var args = ctor.GetParameters().Select(p => p.DefaultValue).ToArray();
- return Activator.CreateInstance(candidateType, args);
- }
- private static IEnumerable<List<Type>> GetPrioritizedGroupsOfCandidateTypes(
- IEnumerable<string> candidateTypeNames)
- {
- return
- candidateTypeNames
- .Select(GetPrioritizedType)
- .Where(x => x != null && x.Enabled)
- .GroupBy(x => x.Priority, item => item.Type)
- .OrderByDescending(g => g.Key)
- .Select(g => g.ToList());
- }
- private static void Warn(IEnumerable<Type> duplicatePriorityTypes, string targetTypesSubMessage)
- {
- const string separator = "\r\n ";
- var message =
- String.Format(
- @"ModuleInitializer.Registrar warning:
- More than one implementation of {0} was discovered with the same priority.
- None of the types were used during module initialization.
- The ambiguous types were:{1}{2}",
- targetTypesSubMessage,
- separator,
- String.Join(separator, duplicatePriorityTypes.Select(t => t.FullName)));
- Trace.WriteLine(message);
- try
- {
- var eventLog = new EventLog(_eventLogName)
- {
- Source = _eventLogSource,
- MachineName = Environment.MachineName
- };
- eventLog.WriteEntry(message, EventLogEntryType.Warning);
- }
- catch (Exception ex)
- {
- Trace.WriteLine(
- String.Format(
- @"Unable to write event log entry with:
- Event log name: {0}
- Event log source: {1}
- Exception Details:
- {2}", _eventLogName, _eventLogSource, ex));
- }
- }
- private static Type ChooseCandidateType(IList<Type> candidateTypes)
- {
- if (candidateTypes.Count == 1)
- {
- return candidateTypes[0];
- }
- return null;
- }
- private static Type ChooseCandidateType<TTargetType, TFactoryType>(IList<Type> candidateTypes)
- {
- if (candidateTypes.Count == 1)
- {
- return candidateTypes[0];
- }
- var targetTypeName = typeof(TTargetType).AssemblyQualifiedName;
- var factoryTypeName = typeof(TFactoryType).AssemblyQualifiedName;
- // Check for the case where only one type implements IEncryptionProviderProvider,
- // and all others only implement IEncryptionProvider. In this case, because
- // IEncryptionProviderProvider has higher priority, use that single type.
- var data =
- candidateTypes.Select(type =>
- {
- var interfaces = type.GetInterfaces();
- return new
- {
- Type = type,
- IsTarget = interfaces.Any(i => i.AssemblyQualifiedName == targetTypeName),
- IsFactory = interfaces.Any(i => i.AssemblyQualifiedName == factoryTypeName)
- };
- }).ToArray();
- if ((data.Count(x => x.IsFactory) == 1)
- && (data.Count(x => x.IsTarget && !x.IsFactory) == (data.Length - 1)))
- {
- return data.Single(x => x.IsFactory).Type;
- }
- return null;
- }
- private static PrioritizedType GetPrioritizedType(string assemblyQualifiedName)
- {
- try
- {
- var type = Type.GetType(assemblyQualifiedName);
- if (type == null)
- {
- return null;
- }
- var registerTypeAttribute = GetRegisterTypeAttribute(type);
- var priority =
- registerTypeAttribute != null
- ? registerTypeAttribute.Priority
- : -1;
- var enabled = registerTypeAttribute == null || registerTypeAttribute.Enabled;
- return new PrioritizedType
- {
- Type = type,
- Priority = priority,
- Enabled = enabled
- };
- }
- catch
- {
- return null;
- }
- }
- private static ModuleInitializer.IRegisterTypeAttribute GetRegisterTypeAttribute(Type type)
- {
- return
- ModuleInitializer.GetProxyRegisterTypeAttribute(type)
- ?? (ModuleInitializer.IRegisterTypeAttribute)Attribute.GetCustomAttribute(type, typeof(RegisterTypeAttribute));
- }
- private static IEnumerable<string> GetCandidateTypeNames<TTargetType>()
- {
- var isTargetType = GetIsTargetTypeFunc<TTargetType>();
- try
- {
- return
- _candidateTypes.Value
- .Where(isTargetType)
- .Select(t => t.AssemblyQualifiedName);
- }
- catch (Exception)
- {
- throw;
- }
- }
- private static Func<Type, bool> GetIsTargetTypeFunc<TTargetType>()
- {
- var targetType = typeof(TTargetType);
- var targetTypeName = targetType.AssemblyQualifiedName;
- if (targetTypeName == null)
- {
- return typeInQuestion => false;
- }
- if (targetType.IsInterface)
- {
- return typeInQuestion =>
- typeInQuestion.GetInterfaces().Any(i => i.AssemblyQualifiedName == targetTypeName);
- }
- if (targetType.IsClass && !targetType.IsSealed)
- {
- return typeInQuestion =>
- {
- var type = typeInQuestion;
- while (type != null)
- {
- if (type.AssemblyQualifiedName == targetTypeName)
- {
- return true;
- }
- type = type.BaseType;
- }
- return false;
- };
- }
- return typeInQuestion => false;
- }
- private static void CheckEventLogSource()
- {
- try
- {
- if (EventLog.SourceExists(_eventLogSource))
- {
- return;
- }
- }
- catch (Exception ex)
- {
- Trace.WriteLine(
- String.Format(
- @"Unable to check the for the existence of event log source: {0}
- {1}", _eventLogSource, ex));
- return;
- }
- try
- {
- EventLog.CreateEventSource(_eventLogSource, _eventLogName);
- }
- catch (Exception ex)
- {
- Trace.WriteLine(String.Format(
- @"Unable to create event log source: {0}
- {1}", _eventLogSource, ex));
- }
- }
- private static ICollection<Type> GetCandidateTypes()
- {
- try
- {
- AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += AppDomainOnReflectionOnlyAssemblyResolve;
- return GetAssemblyFiles().SelectMany(LoadCandidateTypes).ToList();
- }
- finally
- {
- AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= AppDomainOnReflectionOnlyAssemblyResolve;
- }
- }
- private static Assembly AppDomainOnReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args)
- {
- return Assembly.ReflectionOnlyLoad(args.Name);
- }
- private static IEnumerable<string> GetAssemblyFiles()
- {
- try
- {
- return
- Directory.EnumerateFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll")
- .Concat(Directory.EnumerateFiles(AppDomain.CurrentDomain.BaseDirectory, "*.exe"));
- }
- catch
- {
- return Enumerable.Empty<string>();
- }
- }
- private static IEnumerable<Type> LoadCandidateTypes(string assemblyFile)
- {
- try
- {
- var assembly = Assembly.ReflectionOnlyLoadFrom(assemblyFile);
- // Don't look here. And by here, I mean the assembly in which this class, ModuleInitializer, exists.
- if (assembly.FullName == typeof(ModuleInitializer).Assembly.FullName)
- {
- return Enumerable.Empty<Type>();
- }
- return
- assembly.GetTypes()
- .Where(t =>
- t.IsClass
- && !t.IsAbstract
- && t.IsPublic
- && t.AssemblyQualifiedName != null
- && HasDefaultishConstructor(t));
- }
- catch
- {
- return Enumerable.Empty<Type>();
- }
- }
- private static bool HasDefaultishConstructor(Type type)
- {
- return
- type.GetConstructor(Type.EmptyTypes) != null
- || type.GetConstructors().Any(ctor => ctor.GetParameters().All(HasDefaultValue));
- }
- private static bool HasDefaultValue(ParameterInfo parameter)
- {
- const ParameterAttributes hasDefaultValue =
- ParameterAttributes.HasDefault | ParameterAttributes.Optional;
- return (parameter.Attributes & hasDefaultValue) == hasDefaultValue;
- }
- private class PrioritizedType
- {
- public Type Type { get; set; }
- public int Priority { get; set; }
- public bool Enabled { get; set; }
- }
- }
- #endregion
- #region RegisterTypeAttribute
- [AttributeUsage(AttributeTargets.Class)]
- public sealed class RegisterTypeAttribute : Attribute, ModuleInitializer.IRegisterTypeAttribute
- {
- private readonly int _priority;
- public RegisterTypeAttribute()
- : this(0)
- {
- }
- public RegisterTypeAttribute(int priority)
- {
- _priority = priority;
- Enabled = true;
- }
- public int Priority
- {
- get { return _priority; }
- }
- /// <summary>
- /// Gets a value indicating whether this class should be eligible for
- /// automatic registration. The default value is true;
- /// </summary>
- public bool Enabled { get; set; }
- }
- #endregion
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement