BaseApplicationHost.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. using MediaBrowser.Common.Kernel;
  2. using MediaBrowser.Model.Logging;
  3. using MediaBrowser.Model.Serialization;
  4. using SimpleInjector;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Reflection;
  10. using System.Threading;
  11. namespace MediaBrowser.Common.Implementations
  12. {
  13. public abstract class BaseApplicationHost
  14. {
  15. /// <summary>
  16. /// Gets or sets the logger.
  17. /// </summary>
  18. /// <value>The logger.</value>
  19. public ILogger Logger { get; protected set; }
  20. /// <summary>
  21. /// Gets or sets the log manager.
  22. /// </summary>
  23. /// <value>The log manager.</value>
  24. public ILogManager LogManager { get; protected set; }
  25. /// <summary>
  26. /// Gets the application paths.
  27. /// </summary>
  28. /// <value>The application paths.</value>
  29. protected IApplicationPaths ApplicationPaths { get; private set; }
  30. /// <summary>
  31. /// The container
  32. /// </summary>
  33. protected readonly Container Container = new Container();
  34. /// <summary>
  35. /// Gets assemblies that failed to load
  36. /// </summary>
  37. public List<string> FailedAssemblies { get; protected set; }
  38. /// <summary>
  39. /// Gets all types within all running assemblies
  40. /// </summary>
  41. /// <value>All types.</value>
  42. public Type[] AllTypes { get; protected set; }
  43. /// <summary>
  44. /// Gets all concrete types.
  45. /// </summary>
  46. /// <value>All concrete types.</value>
  47. public Type[] AllConcreteTypes { get; protected set; }
  48. /// <summary>
  49. /// The disposable parts
  50. /// </summary>
  51. protected readonly List<IDisposable> DisposableParts = new List<IDisposable>();
  52. /// <summary>
  53. /// Gets a value indicating whether this instance is first run.
  54. /// </summary>
  55. /// <value><c>true</c> if this instance is first run; otherwise, <c>false</c>.</value>
  56. public bool IsFirstRun { get; private set; }
  57. /// <summary>
  58. /// The _protobuf serializer initialized
  59. /// </summary>
  60. private bool _protobufSerializerInitialized;
  61. /// <summary>
  62. /// The _protobuf serializer sync lock
  63. /// </summary>
  64. private object _protobufSerializerSyncLock = new object();
  65. /// <summary>
  66. /// Gets a dynamically compiled generated serializer that can serialize protocontracts without reflection
  67. /// </summary>
  68. private IProtobufSerializer _protobufSerializer;
  69. /// <summary>
  70. /// Gets the protobuf serializer.
  71. /// </summary>
  72. /// <value>The protobuf serializer.</value>
  73. protected IProtobufSerializer ProtobufSerializer
  74. {
  75. get
  76. {
  77. // Lazy load
  78. LazyInitializer.EnsureInitialized(ref _protobufSerializer, ref _protobufSerializerInitialized, ref _protobufSerializerSyncLock, () => Serialization.ProtobufSerializer.Create(AllTypes));
  79. return _protobufSerializer;
  80. }
  81. private set
  82. {
  83. _protobufSerializer = value;
  84. _protobufSerializerInitialized = value != null;
  85. }
  86. }
  87. /// <summary>
  88. /// Initializes a new instance of the <see cref="BaseApplicationHost" /> class.
  89. /// </summary>
  90. protected BaseApplicationHost()
  91. {
  92. FailedAssemblies = new List<string>();
  93. ApplicationPaths = GetApplicationPaths();
  94. LogManager = GetLogManager();
  95. Logger = LogManager.GetLogger("App");
  96. IsFirstRun = !File.Exists(ApplicationPaths.SystemConfigurationFilePath);
  97. DiscoverTypes();
  98. }
  99. /// <summary>
  100. /// Gets the composable part assemblies.
  101. /// </summary>
  102. /// <returns>IEnumerable{Assembly}.</returns>
  103. protected abstract IEnumerable<Assembly> GetComposablePartAssemblies();
  104. /// <summary>
  105. /// Gets the log manager.
  106. /// </summary>
  107. /// <returns>ILogManager.</returns>
  108. protected abstract ILogManager GetLogManager();
  109. /// <summary>
  110. /// Gets the application paths.
  111. /// </summary>
  112. /// <returns>IApplicationPaths.</returns>
  113. protected abstract IApplicationPaths GetApplicationPaths();
  114. /// <summary>
  115. /// Discovers the types.
  116. /// </summary>
  117. protected void DiscoverTypes()
  118. {
  119. FailedAssemblies.Clear();
  120. AllTypes = GetComposablePartAssemblies().SelectMany(GetTypes).ToArray();
  121. AllConcreteTypes = AllTypes.Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType).ToArray();
  122. }
  123. /// <summary>
  124. /// Gets a list of types within an assembly
  125. /// This will handle situations that would normally throw an exception - such as a type within the assembly that depends on some other non-existant reference
  126. /// </summary>
  127. /// <param name="assembly">The assembly.</param>
  128. /// <returns>IEnumerable{Type}.</returns>
  129. /// <exception cref="System.ArgumentNullException">assembly</exception>
  130. protected IEnumerable<Type> GetTypes(Assembly assembly)
  131. {
  132. if (assembly == null)
  133. {
  134. throw new ArgumentNullException("assembly");
  135. }
  136. try
  137. {
  138. return assembly.GetTypes();
  139. }
  140. catch (ReflectionTypeLoadException ex)
  141. {
  142. // If it fails we can still get a list of the Types it was able to resolve
  143. return ex.Types.Where(t => t != null);
  144. }
  145. }
  146. /// <summary>
  147. /// Creates an instance of type and resolves all constructor dependancies
  148. /// </summary>
  149. /// <param name="type">The type.</param>
  150. /// <returns>System.Object.</returns>
  151. public object CreateInstance(Type type)
  152. {
  153. try
  154. {
  155. return Container.GetInstance(type);
  156. }
  157. catch
  158. {
  159. Logger.Error("Error creating {0}", type.Name);
  160. throw;
  161. }
  162. }
  163. /// <summary>
  164. /// Registers the specified obj.
  165. /// </summary>
  166. /// <typeparam name="T"></typeparam>
  167. /// <param name="obj">The obj.</param>
  168. /// <param name="manageLifetime">if set to <c>true</c> [manage lifetime].</param>
  169. protected void RegisterSingleInstance<T>(T obj, bool manageLifetime = true)
  170. where T : class
  171. {
  172. Container.RegisterSingle(obj);
  173. if (manageLifetime)
  174. {
  175. var disposable = obj as IDisposable;
  176. if (disposable != null)
  177. {
  178. Logger.Info("Registering " + disposable.GetType().Name);
  179. DisposableParts.Add(disposable);
  180. }
  181. }
  182. }
  183. /// <summary>
  184. /// Registers the single instance.
  185. /// </summary>
  186. /// <typeparam name="T"></typeparam>
  187. /// <param name="func">The func.</param>
  188. protected void RegisterSingleInstance<T>(Func<T> func)
  189. where T : class
  190. {
  191. Container.RegisterSingle(func);
  192. }
  193. /// <summary>
  194. /// Resolves this instance.
  195. /// </summary>
  196. /// <typeparam name="T"></typeparam>
  197. /// <returns>``0.</returns>
  198. public T Resolve<T>()
  199. {
  200. return (T)Container.GetRegistration(typeof(T), true).GetInstance();
  201. }
  202. /// <summary>
  203. /// Resolves this instance.
  204. /// </summary>
  205. /// <typeparam name="T"></typeparam>
  206. /// <returns>``0.</returns>
  207. public T TryResolve<T>()
  208. {
  209. var result = Container.GetRegistration(typeof(T), false);
  210. if (result == null)
  211. {
  212. return default(T);
  213. }
  214. return (T)result.GetInstance();
  215. }
  216. /// <summary>
  217. /// Loads the assembly.
  218. /// </summary>
  219. /// <param name="file">The file.</param>
  220. /// <returns>Assembly.</returns>
  221. protected Assembly LoadAssembly(string file)
  222. {
  223. try
  224. {
  225. return Assembly.Load(File.ReadAllBytes((file)));
  226. }
  227. catch (Exception ex)
  228. {
  229. FailedAssemblies.Add(file);
  230. Logger.ErrorException("Error loading assembly {0}", ex, file);
  231. return null;
  232. }
  233. }
  234. /// <summary>
  235. /// Gets the exports.
  236. /// </summary>
  237. /// <typeparam name="T"></typeparam>
  238. /// <param name="manageLiftime">if set to <c>true</c> [manage liftime].</param>
  239. /// <returns>IEnumerable{``0}.</returns>
  240. public IEnumerable<T> GetExports<T>(bool manageLiftime = true)
  241. {
  242. var currentType = typeof(T);
  243. Logger.Info("Composing instances of " + currentType.Name);
  244. var parts = AllConcreteTypes.Where(currentType.IsAssignableFrom).Select(CreateInstance).Cast<T>().ToArray();
  245. if (manageLiftime)
  246. {
  247. DisposableParts.AddRange(parts.OfType<IDisposable>());
  248. }
  249. return parts;
  250. }
  251. /// <summary>
  252. /// Gets the current application version
  253. /// </summary>
  254. /// <value>The application version.</value>
  255. public Version ApplicationVersion
  256. {
  257. get
  258. {
  259. return GetType().Assembly.GetName().Version;
  260. }
  261. }
  262. /// <summary>
  263. /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
  264. /// </summary>
  265. public void Dispose()
  266. {
  267. Dispose(true);
  268. }
  269. /// <summary>
  270. /// Releases unmanaged and - optionally - managed resources.
  271. /// </summary>
  272. /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
  273. protected virtual void Dispose(bool dispose)
  274. {
  275. if (dispose)
  276. {
  277. var type = GetType();
  278. Logger.Info("Disposing " + type.Name);
  279. var parts = DisposableParts.Distinct().Where(i => i.GetType() != type).ToList();
  280. DisposableParts.Clear();
  281. foreach (var part in parts)
  282. {
  283. Logger.Info("Disposing " + part.GetType().Name);
  284. part.Dispose();
  285. }
  286. }
  287. }
  288. }
  289. }