Advertisement
Guest User

Untitled

a guest
Dec 18th, 2014
132
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.63 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Reflection;
  7.  
  8. namespace Demo
  9. {
  10. /// <summary>
  11. /// This class defines the static registration behavior of this assembly.
  12. /// </summary>
  13. /// <remarks>
  14. /// The implementation of the module initialization mechanism relies on
  15. /// an single internal or public class, contained in any namespace, named
  16. /// "ModuleInitializer". It is vitally important that the signature of this
  17. /// class be exactly: internal|public static class ModuleInitializer
  18. /// </remarks>
  19. internal static class ModuleInitializer
  20. {
  21. private static void RegisterTypes()
  22. {
  23. // TODO: Delete the example registrations below, and add registrations for your library.
  24.  
  25. // You can register a specific type.
  26. Registrar.Register<IFoo>(foo => Foo.Current = foo);
  27.  
  28. // Or you can register a specific type along with a factory that creates instances of that type.
  29. Registrar.Register<IBar, IBarFactory>(bar => Bar.Current = bar, factory => factory.GetBar());
  30. }
  31.  
  32. #region Extension Points (TODO: Customize as necessary)
  33.  
  34. // TODO: Implement a mechanism for reversing the default TFactoryType-over-TTargetType priority.
  35.  
  36. internal static ProxyRegisterTypeAttribute GetProxyRegisterTypeAttribute(Type type)
  37. {
  38. // NOTE: To disable this extension point, return null.
  39.  
  40. // TODO: Replace 'ExportAttribute' with your attribute type.
  41. var attribute = (ExportAttribute)Attribute.GetCustomAttribute(type, typeof(ExportAttribute));
  42.  
  43. return
  44. attribute == null
  45. ? null
  46. : new ProxyRegisterTypeAttribute(
  47. // TODO: Replace 'attribute.HighPriority ? 1 : -2' with however you get a priority value.
  48. () => attribute.HighPriority ? 1 : -2,
  49.  
  50. // TODO: Replace 'true' with however you get an enabled value.
  51. () => true);
  52. }
  53.  
  54. #endregion
  55.  
  56. #region Don't change anything in this region
  57.  
  58. internal interface IRegisterTypeAttribute
  59. {
  60. int Priority { get; }
  61. bool Enabled { get; }
  62. }
  63.  
  64. /// <summary>
  65. /// This is the entry point of an assembly upon being loaded for the first time.
  66. /// It is not intended to be used directly.
  67. /// </summary>
  68. /// <remarks>
  69. /// The implementation of the module initialization mechanism relies on
  70. /// a void method named "Run" with no parameters. It is vitally important
  71. /// that the signature be exactly: internal static void Run()
  72. /// </remarks>
  73. internal static void Run()
  74. {
  75. RegisterTypes();
  76. Registrar.TearDown();
  77. }
  78.  
  79. internal class ProxyRegisterTypeAttribute : IRegisterTypeAttribute
  80. {
  81. private readonly Func<int> _getPriorityFunc;
  82. private readonly Func<bool> _getEnabledFunc;
  83.  
  84. public ProxyRegisterTypeAttribute(
  85. Func<int> getPriorityFunc,
  86. Func<bool> getEnabledFunc)
  87. {
  88. _getPriorityFunc = getPriorityFunc;
  89. _getEnabledFunc = getEnabledFunc;
  90. }
  91.  
  92. public int Priority { get { return _getPriorityFunc(); } }
  93. public bool Enabled { get { return _getEnabledFunc(); } }
  94. }
  95.  
  96. #endregion
  97. }
  98.  
  99. #region Registrar
  100.  
  101. internal static class Registrar
  102. {
  103. private const string _eventLogSource = ".NET Runtime";
  104. private const string _eventLogName = "Application";
  105.  
  106. private static Lazy<ICollection<Type>> _candidateTypes;
  107.  
  108. static Registrar()
  109. {
  110. CheckEventLogSource();
  111. _candidateTypes = new Lazy<ICollection<Type>>(GetCandidateTypes);
  112. }
  113.  
  114. public static void Register<TTargetType>(Action<TTargetType> registerAction)
  115. where TTargetType : class
  116. {
  117. var prioritizedGroupsOfCandidateTypes =
  118. GetPrioritizedGroupsOfCandidateTypes(
  119. GetCandidateTypeNames<TTargetType>());
  120.  
  121. foreach (var candidateTypes in prioritizedGroupsOfCandidateTypes)
  122. {
  123. var candidateType = ChooseCandidateType(candidateTypes);
  124.  
  125. if (candidateType == null)
  126. {
  127. Warn(candidateTypes, typeof(TTargetType).FullName);
  128. }
  129. else
  130. {
  131. var instance = GetTargetInstance<TTargetType>(candidateType);
  132.  
  133. if (instance != null)
  134. {
  135. registerAction(instance);
  136. return;
  137. }
  138. }
  139. }
  140. }
  141.  
  142. public static void Register<TTargetType, TFactoryType>(
  143. Action<TTargetType> registerAction,
  144. Func<TFactoryType, TTargetType> createTargetFunc)
  145. where TTargetType : class
  146. where TFactoryType : class
  147. {
  148. var prioritizedGroupsOfCandidateTypes =
  149. GetPrioritizedGroupsOfCandidateTypes(
  150. GetCandidateTypeNames<TTargetType>()
  151. .Concat(GetCandidateTypeNames<TFactoryType>()));
  152.  
  153. foreach (var candidateTypes in prioritizedGroupsOfCandidateTypes)
  154. {
  155. var candidateType = ChooseCandidateType<TTargetType, TFactoryType>(candidateTypes);
  156.  
  157. if (candidateType == null)
  158. {
  159. Warn(
  160. candidateTypes,
  161. string.Format(
  162. "either {0} or {1}",
  163. typeof(TFactoryType).FullName,
  164. typeof(TTargetType).FullName));
  165. }
  166. else
  167. {
  168. var instance = GetTargetInstance(candidateType, createTargetFunc);
  169.  
  170. if (instance != null)
  171. {
  172. registerAction(instance);
  173. return;
  174. }
  175. }
  176. }
  177. }
  178.  
  179. public static void TearDown()
  180. {
  181. _candidateTypes = null;
  182. }
  183.  
  184. private static TTargetType GetTargetInstance<TTargetType>(Type candidateType)
  185. where TTargetType : class
  186. {
  187. try
  188. {
  189. var instance = Instantiate(candidateType);
  190.  
  191. var target = instance as TTargetType;
  192. if (target != null)
  193. {
  194. return target;
  195. }
  196.  
  197. return null;
  198. }
  199. catch
  200. {
  201. return null;
  202. }
  203. }
  204.  
  205. private static TTargetType GetTargetInstance<TTargetType, TFactoryType>(
  206. Type candidateType,
  207. Func<TFactoryType, TTargetType> createTargetFunc)
  208. where TTargetType : class
  209. where TFactoryType : class
  210. {
  211. try
  212. {
  213. var instance = Instantiate(candidateType);
  214.  
  215. var factory = instance as TFactoryType;
  216. if (factory != null)
  217. {
  218. return createTargetFunc(factory);
  219. }
  220.  
  221. var target = instance as TTargetType;
  222. if (target != null)
  223. {
  224. return target;
  225. }
  226.  
  227. return null;
  228. }
  229. catch
  230. {
  231. return null;
  232. }
  233. }
  234.  
  235. private static object Instantiate(Type candidateType)
  236. {
  237. if (candidateType.GetConstructor(Type.EmptyTypes) != null)
  238. {
  239. return Activator.CreateInstance(candidateType);
  240. }
  241.  
  242. var ctor =
  243. candidateType.GetConstructors()
  244. .OrderByDescending(c => c.GetParameters().Length)
  245. .First(c => c.GetParameters().All(HasDefaultValue));
  246.  
  247. var args = ctor.GetParameters().Select(p => p.DefaultValue).ToArray();
  248.  
  249. return Activator.CreateInstance(candidateType, args);
  250. }
  251.  
  252. private static IEnumerable<List<Type>> GetPrioritizedGroupsOfCandidateTypes(
  253. IEnumerable<string> candidateTypeNames)
  254. {
  255. return
  256. candidateTypeNames
  257. .Select(GetPrioritizedType)
  258. .Where(x => x != null && x.Enabled)
  259. .GroupBy(x => x.Priority, item => item.Type)
  260. .OrderByDescending(g => g.Key)
  261. .Select(g => g.ToList());
  262. }
  263.  
  264. private static void Warn(IEnumerable<Type> duplicatePriorityTypes, string targetTypesSubMessage)
  265. {
  266. const string separator = "\r\n ";
  267.  
  268. var message =
  269. String.Format(
  270. @"ModuleInitializer.Registrar warning:
  271. More than one implementation of {0} was discovered with the same priority.
  272. None of the types were used during module initialization.
  273. The ambiguous types were:{1}{2}",
  274. targetTypesSubMessage,
  275. separator,
  276. String.Join(separator, duplicatePriorityTypes.Select(t => t.FullName)));
  277.  
  278. Trace.WriteLine(message);
  279.  
  280. try
  281. {
  282. var eventLog = new EventLog(_eventLogName)
  283. {
  284. Source = _eventLogSource,
  285. MachineName = Environment.MachineName
  286. };
  287.  
  288. eventLog.WriteEntry(message, EventLogEntryType.Warning);
  289. }
  290. catch (Exception ex)
  291. {
  292. Trace.WriteLine(
  293. String.Format(
  294. @"Unable to write event log entry with:
  295. Event log name: {0}
  296. Event log source: {1}
  297.  
  298. Exception Details:
  299. {2}", _eventLogName, _eventLogSource, ex));
  300. }
  301. }
  302.  
  303. private static Type ChooseCandidateType(IList<Type> candidateTypes)
  304. {
  305. if (candidateTypes.Count == 1)
  306. {
  307. return candidateTypes[0];
  308. }
  309.  
  310. return null;
  311. }
  312.  
  313. private static Type ChooseCandidateType<TTargetType, TFactoryType>(IList<Type> candidateTypes)
  314. {
  315. if (candidateTypes.Count == 1)
  316. {
  317. return candidateTypes[0];
  318. }
  319.  
  320. var targetTypeName = typeof(TTargetType).AssemblyQualifiedName;
  321. var factoryTypeName = typeof(TFactoryType).AssemblyQualifiedName;
  322.  
  323. // Check for the case where only one type implements IEncryptionProviderProvider,
  324. // and all others only implement IEncryptionProvider. In this case, because
  325. // IEncryptionProviderProvider has higher priority, use that single type.
  326. var data =
  327. candidateTypes.Select(type =>
  328. {
  329. var interfaces = type.GetInterfaces();
  330.  
  331. return new
  332. {
  333. Type = type,
  334. IsTarget = interfaces.Any(i => i.AssemblyQualifiedName == targetTypeName),
  335. IsFactory = interfaces.Any(i => i.AssemblyQualifiedName == factoryTypeName)
  336. };
  337. }).ToArray();
  338.  
  339. if ((data.Count(x => x.IsFactory) == 1)
  340. && (data.Count(x => x.IsTarget && !x.IsFactory) == (data.Length - 1)))
  341. {
  342. return data.Single(x => x.IsFactory).Type;
  343. }
  344.  
  345. return null;
  346. }
  347.  
  348. private static PrioritizedType GetPrioritizedType(string assemblyQualifiedName)
  349. {
  350. try
  351. {
  352. var type = Type.GetType(assemblyQualifiedName);
  353.  
  354. if (type == null)
  355. {
  356. return null;
  357. }
  358.  
  359. var registerTypeAttribute = GetRegisterTypeAttribute(type);
  360.  
  361. var priority =
  362. registerTypeAttribute != null
  363. ? registerTypeAttribute.Priority
  364. : -1;
  365.  
  366. var enabled = registerTypeAttribute == null || registerTypeAttribute.Enabled;
  367.  
  368. return new PrioritizedType
  369. {
  370. Type = type,
  371. Priority = priority,
  372. Enabled = enabled
  373. };
  374. }
  375. catch
  376. {
  377. return null;
  378. }
  379. }
  380.  
  381. private static ModuleInitializer.IRegisterTypeAttribute GetRegisterTypeAttribute(Type type)
  382. {
  383. return
  384. ModuleInitializer.GetProxyRegisterTypeAttribute(type)
  385. ?? (ModuleInitializer.IRegisterTypeAttribute)Attribute.GetCustomAttribute(type, typeof(RegisterTypeAttribute));
  386. }
  387.  
  388. private static IEnumerable<string> GetCandidateTypeNames<TTargetType>()
  389. {
  390. var isTargetType = GetIsTargetTypeFunc<TTargetType>();
  391.  
  392. try
  393. {
  394. return
  395. _candidateTypes.Value
  396. .Where(isTargetType)
  397. .Select(t => t.AssemblyQualifiedName);
  398. }
  399. catch (Exception)
  400. {
  401. throw;
  402. }
  403. }
  404.  
  405. private static Func<Type, bool> GetIsTargetTypeFunc<TTargetType>()
  406. {
  407. var targetType = typeof(TTargetType);
  408. var targetTypeName = targetType.AssemblyQualifiedName;
  409.  
  410. if (targetTypeName == null)
  411. {
  412. return typeInQuestion => false;
  413. }
  414.  
  415. if (targetType.IsInterface)
  416. {
  417. return typeInQuestion =>
  418. typeInQuestion.GetInterfaces().Any(i => i.AssemblyQualifiedName == targetTypeName);
  419. }
  420.  
  421. if (targetType.IsClass && !targetType.IsSealed)
  422. {
  423. return typeInQuestion =>
  424. {
  425. var type = typeInQuestion;
  426.  
  427. while (type != null)
  428. {
  429. if (type.AssemblyQualifiedName == targetTypeName)
  430. {
  431. return true;
  432. }
  433.  
  434. type = type.BaseType;
  435. }
  436.  
  437. return false;
  438. };
  439. }
  440.  
  441. return typeInQuestion => false;
  442. }
  443.  
  444. private static void CheckEventLogSource()
  445. {
  446. try
  447. {
  448. if (EventLog.SourceExists(_eventLogSource))
  449. {
  450. return;
  451. }
  452. }
  453. catch (Exception ex)
  454. {
  455. Trace.WriteLine(
  456. String.Format(
  457. @"Unable to check the for the existence of event log source: {0}
  458.  
  459. {1}", _eventLogSource, ex));
  460.  
  461. return;
  462. }
  463.  
  464. try
  465. {
  466. EventLog.CreateEventSource(_eventLogSource, _eventLogName);
  467. }
  468. catch (Exception ex)
  469. {
  470. Trace.WriteLine(String.Format(
  471. @"Unable to create event log source: {0}
  472.  
  473. {1}", _eventLogSource, ex));
  474. }
  475. }
  476.  
  477. private static ICollection<Type> GetCandidateTypes()
  478. {
  479. try
  480. {
  481. AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += AppDomainOnReflectionOnlyAssemblyResolve;
  482. return GetAssemblyFiles().SelectMany(LoadCandidateTypes).ToList();
  483. }
  484. finally
  485. {
  486. AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= AppDomainOnReflectionOnlyAssemblyResolve;
  487. }
  488. }
  489.  
  490. private static Assembly AppDomainOnReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args)
  491. {
  492. return Assembly.ReflectionOnlyLoad(args.Name);
  493. }
  494.  
  495. private static IEnumerable<string> GetAssemblyFiles()
  496. {
  497. try
  498. {
  499. return
  500. Directory.EnumerateFiles(AppDomain.CurrentDomain.BaseDirectory, "*.dll")
  501. .Concat(Directory.EnumerateFiles(AppDomain.CurrentDomain.BaseDirectory, "*.exe"));
  502. }
  503. catch
  504. {
  505. return Enumerable.Empty<string>();
  506. }
  507. }
  508.  
  509. private static IEnumerable<Type> LoadCandidateTypes(string assemblyFile)
  510. {
  511. try
  512. {
  513. var assembly = Assembly.ReflectionOnlyLoadFrom(assemblyFile);
  514.  
  515. // Don't look here. And by here, I mean the assembly in which this class, ModuleInitializer, exists.
  516. if (assembly.FullName == typeof(ModuleInitializer).Assembly.FullName)
  517. {
  518. return Enumerable.Empty<Type>();
  519. }
  520.  
  521. return
  522. assembly.GetTypes()
  523. .Where(t =>
  524. t.IsClass
  525. && !t.IsAbstract
  526. && t.IsPublic
  527. && t.AssemblyQualifiedName != null
  528. && HasDefaultishConstructor(t));
  529. }
  530. catch
  531. {
  532. return Enumerable.Empty<Type>();
  533. }
  534. }
  535.  
  536. private static bool HasDefaultishConstructor(Type type)
  537. {
  538. return
  539. type.GetConstructor(Type.EmptyTypes) != null
  540. || type.GetConstructors().Any(ctor => ctor.GetParameters().All(HasDefaultValue));
  541. }
  542.  
  543. private static bool HasDefaultValue(ParameterInfo parameter)
  544. {
  545. const ParameterAttributes hasDefaultValue =
  546. ParameterAttributes.HasDefault | ParameterAttributes.Optional;
  547.  
  548. return (parameter.Attributes & hasDefaultValue) == hasDefaultValue;
  549. }
  550.  
  551. private class PrioritizedType
  552. {
  553. public Type Type { get; set; }
  554. public int Priority { get; set; }
  555. public bool Enabled { get; set; }
  556. }
  557. }
  558.  
  559. #endregion
  560.  
  561. #region RegisterTypeAttribute
  562.  
  563. [AttributeUsage(AttributeTargets.Class)]
  564. public sealed class RegisterTypeAttribute : Attribute, ModuleInitializer.IRegisterTypeAttribute
  565. {
  566. private readonly int _priority;
  567.  
  568. public RegisterTypeAttribute()
  569. : this(0)
  570. {
  571. }
  572.  
  573. public RegisterTypeAttribute(int priority)
  574. {
  575. _priority = priority;
  576. Enabled = true;
  577. }
  578.  
  579. public int Priority
  580. {
  581. get { return _priority; }
  582. }
  583.  
  584. /// <summary>
  585. /// Gets a value indicating whether this class should be eligible for
  586. /// automatic registration. The default value is true;
  587. /// </summary>
  588. public bool Enabled { get; set; }
  589. }
  590.  
  591. #endregion
  592. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement