From a2d215b6ae9d594d71a679a464c9c6a559efe862 Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Fri, 22 Feb 2013 19:24:50 -0500 Subject: added simple injector for dependancy management --- MediaBrowser.Common/Kernel/BaseKernel.cs | 153 +++++++++++++++++++++++++++---- 1 file changed, 137 insertions(+), 16 deletions(-) (limited to 'MediaBrowser.Common/Kernel/BaseKernel.cs') diff --git a/MediaBrowser.Common/Kernel/BaseKernel.cs b/MediaBrowser.Common/Kernel/BaseKernel.cs index 2b3986408..91965e469 100644 --- a/MediaBrowser.Common/Kernel/BaseKernel.cs +++ b/MediaBrowser.Common/Kernel/BaseKernel.cs @@ -1,7 +1,5 @@ using MediaBrowser.Common.Events; using MediaBrowser.Common.IO; -using MediaBrowser.Common.Localization; -using MediaBrowser.Common.Mef; using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.ScheduledTasks; @@ -13,12 +11,14 @@ using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; +using System.ComponentModel.Composition.Primitives; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; +using SimpleInjector; namespace MediaBrowser.Common.Kernel { @@ -200,13 +200,6 @@ namespace MediaBrowser.Common.Kernel [ImportMany(typeof(IWebSocketListener))] public IEnumerable WebSocketListeners { get; private set; } - /// - /// Gets the list of Localized string files - /// - /// The string files. - [ImportMany(typeof(LocalizedStringData))] - public IEnumerable StringFiles { get; private set; } - /// /// Gets the MEF CompositionContainer /// @@ -241,7 +234,6 @@ namespace MediaBrowser.Common.Kernel /// Gets the rest services. /// /// The rest services. - [ImportMany(typeof(IRestfulService))] public IEnumerable RestServices { get; private set; } /// @@ -265,7 +257,7 @@ namespace MediaBrowser.Common.Kernel get { // Lazy load - LazyInitializer.EnsureInitialized(ref _protobufSerializer, ref _protobufSerializerInitialized, ref _protobufSerializerSyncLock, () => DynamicProtobufSerializer.Create(Assemblies)); + LazyInitializer.EnsureInitialized(ref _protobufSerializer, ref _protobufSerializerInitialized, ref _protobufSerializerSyncLock, () => DynamicProtobufSerializer.Create(AllTypes)); return _protobufSerializer; } private set @@ -341,6 +333,12 @@ namespace MediaBrowser.Common.Kernel /// The assemblies. public Assembly[] Assemblies { get; private set; } + /// + /// Gets all types. + /// + /// All types. + public Type[] AllTypes { get; private set; } + /// /// Initializes a new instance of the class. /// @@ -460,25 +458,83 @@ namespace MediaBrowser.Common.Kernel Assemblies = GetComposablePartAssemblies().ToArray(); - CompositionContainer = MefUtils.GetSafeCompositionContainer(Assemblies.Select(i => new AssemblyCatalog(i))); - - ComposeExportedValues(CompositionContainer); + AllTypes = Assemblies.SelectMany(GetTypes).ToArray(); - CompositionContainer.ComposeParts(this); + ComposeParts(AllTypes); await OnComposablePartsLoaded().ConfigureAwait(false); CompositionContainer.Catalog.Dispose(); } + /// + /// The ioc container + /// + private readonly Container _iocContainer = new Container(); + + /// + /// Composes the parts. + /// + /// All types. + private void ComposeParts(IEnumerable allTypes) + { + var concreteTypes = allTypes.Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType).ToArray(); + + CompositionContainer = GetSafeCompositionContainer(concreteTypes.Select(i => new TypeCatalog(i))); + + ComposeExportedValues(CompositionContainer, _iocContainer); + + CompositionContainer.ComposeParts(this); + + ComposePartsWithIocContainer(concreteTypes, _iocContainer); + } + + /// + /// Composes the parts with ioc container. + /// + /// All types. + /// The container. + protected virtual void ComposePartsWithIocContainer(Type[] allTypes, Container container) + { + RestServices = GetExports(allTypes); + } + + /// + /// Gets the exports. + /// + /// + /// All types. + /// IEnumerable{``0}. + protected IEnumerable GetExports(Type[] allTypes) + { + var currentType = typeof(T); + + Logger.Info("Composing instances of " + currentType.Name); + + return allTypes.Where(currentType.IsAssignableFrom).Select(Instantiate).Cast().ToArray(); + } + + /// + /// Instantiates the specified type. + /// + /// The type. + /// System.Object. + private object Instantiate(Type type) + { + return _iocContainer.GetInstance(type); + } + /// /// Composes the exported values. /// /// The container. - protected virtual void ComposeExportedValues(CompositionContainer container) + protected virtual void ComposeExportedValues(CompositionContainer container, Container iocContainer) { container.ComposeExportedValue("logger", Logger); container.ComposeExportedValue("appHost", ApplicationHost); + + iocContainer.RegisterSingle(Logger); + iocContainer.RegisterSingle(ApplicationHost); } /// @@ -545,6 +601,71 @@ namespace MediaBrowser.Common.Kernel yield return GetType().Assembly; } + /// + /// Plugins that live on both the server and UI are going to have references to assemblies from both sides. + /// But looks for Parts on one side, it will throw an exception when it seems Types from the other side that it doesn't have a reference to. + /// For example, a plugin provides a Resolver. When MEF runs in the UI, it will throw an exception when it sees the resolver because there won't be a reference to the base class. + /// This method will catch those exceptions while retining the list of Types that MEF is able to resolve. + /// + /// The catalogs. + /// CompositionContainer. + /// catalogs + private static CompositionContainer GetSafeCompositionContainer(IEnumerable catalogs) + { + if (catalogs == null) + { + throw new ArgumentNullException("catalogs"); + } + + var newList = new List(); + + // Go through each Catalog + foreach (var catalog in catalogs) + { + try + { + // Try to have MEF find Parts + catalog.Parts.ToArray(); + + // If it succeeds we can use the entire catalog + newList.Add(catalog); + } + catch (ReflectionTypeLoadException ex) + { + // If it fails we can still get a list of the Types it was able to resolve and create TypeCatalogs + var typeCatalogs = ex.Types.Where(t => t != null).Select(t => new TypeCatalog(t)); + newList.AddRange(typeCatalogs); + } + } + + return new CompositionContainer(new AggregateCatalog(newList)); + } + + /// + /// Gets a list of types within an assembly + /// 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 + /// + /// The assembly. + /// IEnumerable{Type}. + /// assembly + private static IEnumerable GetTypes(Assembly assembly) + { + if (assembly == null) + { + throw new ArgumentNullException("assembly"); + } + + try + { + return assembly.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { + // If it fails we can still get a list of the Types it was able to resolve + return ex.Types.Where(t => t != null); + } + } + /// /// Fires after MEF finishes finding composable parts within plugin assemblies /// -- cgit v1.2.3