1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Collections.Generic; 6 using System.Composition.Convention; 7 using System.Composition.Debugging; 8 using System.Composition.Hosting.Core; 9 using System.Composition.TypedParts; 10 using System.Composition.TypedParts.Util; 11 using System.Diagnostics; 12 using System.Linq; 13 using System.Reflection; 14 15 namespace System.Composition.Hosting 16 { 17 /// <summary> 18 /// Configures and constructs a lightweight container. 19 /// </summary> 20 [DebuggerTypeProxy(typeof(ContainerConfigurationDebuggerProxy))] 21 public class ContainerConfiguration 22 { 23 private AttributedModelProvider _defaultAttributeContext; 24 private readonly IList<ExportDescriptorProvider> _addedSources = new List<ExportDescriptorProvider>(); 25 private readonly IList<Tuple<IEnumerable<Type>, AttributedModelProvider>> _types = new List<Tuple<IEnumerable<Type>, AttributedModelProvider>>(); 26 27 /// <summary> 28 /// Create the container. The value returned from this method provides 29 /// the exports in the container, as well as a means to dispose the container. 30 /// </summary> 31 /// <returns>The container.</returns> CreateContainer()32 public CompositionHost CreateContainer() 33 { 34 var providers = _addedSources.ToList(); 35 36 foreach (var typeSet in _types) 37 { 38 var ac = typeSet.Item2 ?? _defaultAttributeContext ?? new DirectAttributeContext(); 39 40 providers.Add(new TypedPartExportDescriptorProvider(typeSet.Item1, ac)); 41 } 42 43 return CompositionHost.CreateCompositionHost(providers.ToArray()); 44 } 45 46 /// <summary> 47 /// Add an export descriptor provider to the container. 48 /// </summary> 49 /// <param name="exportDescriptorProvider">An export descriptor provider.</param> 50 /// <returns>A configuration object allowing configuration to continue.</returns> WithProvider(ExportDescriptorProvider exportDescriptorProvider)51 public ContainerConfiguration WithProvider(ExportDescriptorProvider exportDescriptorProvider) 52 { 53 if (exportDescriptorProvider == null) throw new ArgumentNullException(nameof(exportDescriptorProvider)); 54 _addedSources.Add(exportDescriptorProvider); 55 return this; 56 } 57 58 /// <summary> 59 /// Add conventions defined using a <see cref="AttributedModelProvider"/> to the container. 60 /// These will be used as the default conventions; types and assemblies added with a 61 /// specific convention will use their own. 62 /// </summary> 63 /// <param name="conventions"></param> 64 /// <returns>A configuration object allowing configuration to continue.</returns> WithDefaultConventions(AttributedModelProvider conventions)65 public ContainerConfiguration WithDefaultConventions(AttributedModelProvider conventions) 66 { 67 if (conventions == null) throw new ArgumentNullException(nameof(conventions)); 68 69 if (_defaultAttributeContext != null) 70 throw new InvalidOperationException(SR.ContainerConfiguration_DefaultConventionSet); 71 72 _defaultAttributeContext = conventions; 73 return this; 74 } 75 76 /// <summary> 77 /// Add a part type to the container. If the part type does not have any exports it 78 /// will be ignored. 79 /// </summary> 80 /// <param name="partType">The part type.</param> 81 /// <returns>A configuration object allowing configuration to continue.</returns> WithPart(Type partType)82 public ContainerConfiguration WithPart(Type partType) 83 { 84 return WithPart(partType, null); 85 } 86 87 /// <summary> 88 /// Add a part type to the container. If the part type does not have any exports it 89 /// will be ignored. 90 /// </summary> 91 /// <param name="partType">The part type.</param> 92 /// <param name="conventions">Conventions represented by a <see cref="AttributedModelProvider"/>, or null.</param> 93 /// <returns>A configuration object allowing configuration to continue.</returns> WithPart(Type partType, AttributedModelProvider conventions)94 public ContainerConfiguration WithPart(Type partType, AttributedModelProvider conventions) 95 { 96 if (partType == null) throw new ArgumentNullException(nameof(partType)); 97 return WithParts(new[] { partType }, conventions); 98 } 99 100 /// <summary> 101 /// Add a part type to the container. If the part type does not have any exports it 102 /// will be ignored. 103 /// </summary> 104 /// <typeparam name="TPart">The part type.</typeparam> 105 /// <returns>A configuration object allowing configuration to continue.</returns> WithPart()106 public ContainerConfiguration WithPart<TPart>() 107 { 108 return WithPart<TPart>(null); 109 } 110 111 /// <summary> 112 /// Add a part type to the container. If the part type does not have any exports it 113 /// will be ignored. 114 /// </summary> 115 /// <typeparam name="TPart">The part type.</typeparam> 116 /// <param name="conventions">Conventions represented by a <see cref="AttributedModelProvider"/>, or null.</param> 117 /// <returns>A configuration object allowing configuration to continue.</returns> WithPart(AttributedModelProvider conventions)118 public ContainerConfiguration WithPart<TPart>(AttributedModelProvider conventions) 119 { 120 return WithPart(typeof(TPart), conventions); 121 } 122 123 /// <summary> 124 /// Add part types to the container. If a part type does not have any exports it 125 /// will be ignored. 126 /// </summary> 127 /// <param name="partTypes">The part types.</param> 128 /// <returns>A configuration object allowing configuration to continue.</returns> WithParts(params Type[] partTypes)129 public ContainerConfiguration WithParts(params Type[] partTypes) 130 { 131 return WithParts((IEnumerable<Type>)partTypes); 132 } 133 134 /// <summary> 135 /// Add part types to the container. If a part type does not have any exports it 136 /// will be ignored. 137 /// </summary> 138 /// <param name="partTypes">The part types.</param> 139 /// <returns>A configuration object allowing configuration to continue.</returns> WithParts(IEnumerable<Type> partTypes)140 public ContainerConfiguration WithParts(IEnumerable<Type> partTypes) 141 { 142 return WithParts(partTypes, null); 143 } 144 145 /// <summary> 146 /// Add part types to the container. If a part type does not have any exports it 147 /// will be ignored. 148 /// </summary> 149 /// <param name="partTypes">The part types.</param> 150 /// <param name="conventions">Conventions represented by a <see cref="AttributedModelProvider"/>, or null.</param> 151 /// <returns>A configuration object allowing configuration to continue.</returns> WithParts(IEnumerable<Type> partTypes, AttributedModelProvider conventions)152 public ContainerConfiguration WithParts(IEnumerable<Type> partTypes, AttributedModelProvider conventions) 153 { 154 if (partTypes == null) throw new ArgumentNullException(nameof(partTypes)); 155 _types.Add(Tuple.Create(partTypes, conventions)); 156 return this; 157 } 158 159 /// <summary> 160 /// Add part types from an assembly to the container. If a part type does not have any exports it 161 /// will be ignored. 162 /// </summary> 163 /// <param name="assembly">The assembly from which to add part types.</param> 164 /// <returns>A configuration object allowing configuration to continue.</returns> WithAssembly(Assembly assembly)165 public ContainerConfiguration WithAssembly(Assembly assembly) 166 { 167 return WithAssembly(assembly, null); 168 } 169 170 /// <summary> 171 /// Add part types from an assembly to the container. If a part type does not have any exports it 172 /// will be ignored. 173 /// </summary> 174 /// <param name="assembly">The assembly from which to add part types.</param> 175 /// <param name="conventions">Conventions represented by a <see cref="AttributedModelProvider"/>, or null.</param> 176 /// <returns>A configuration object allowing configuration to continue.</returns> WithAssembly(Assembly assembly, AttributedModelProvider conventions)177 public ContainerConfiguration WithAssembly(Assembly assembly, AttributedModelProvider conventions) 178 { 179 return WithAssemblies(new[] { assembly }, conventions); 180 } 181 182 /// <summary> 183 /// Add part types from a list of assemblies to the container. If a part type does not have any exports it 184 /// will be ignored. 185 /// </summary> 186 /// <param name="assemblies">Assemblies containing part types.</param> 187 /// <returns>A configuration object allowing configuration to continue.</returns> WithAssemblies(IEnumerable<Assembly> assemblies)188 public ContainerConfiguration WithAssemblies(IEnumerable<Assembly> assemblies) 189 { 190 return WithAssemblies(assemblies, null); 191 } 192 193 /// <summary> 194 /// Add part types from a list of assemblies to the container. If a part type does not have any exports it 195 /// will be ignored. 196 /// </summary> 197 /// <param name="assemblies">Assemblies containing part types.</param> 198 /// <param name="conventions">Conventions represented by a <see cref="AttributedModelProvider"/>, or null.</param> 199 /// <returns>A configuration object allowing configuration to continue.</returns> WithAssemblies(IEnumerable<Assembly> assemblies, AttributedModelProvider conventions)200 public ContainerConfiguration WithAssemblies(IEnumerable<Assembly> assemblies, AttributedModelProvider conventions) 201 { 202 if (assemblies == null) throw new ArgumentNullException(nameof(assemblies)); 203 return WithParts(assemblies.SelectMany(a => a.DefinedTypes.Select(dt => dt.AsType())), conventions); 204 } 205 DebugGetAddedExportDescriptorProviders()206 internal ExportDescriptorProvider[] DebugGetAddedExportDescriptorProviders() 207 { 208 return _addedSources.ToArray(); 209 } 210 DebugGetRegisteredTypes()211 internal Tuple<IEnumerable<Type>, AttributedModelProvider>[] DebugGetRegisteredTypes() 212 { 213 return _types.ToArray(); 214 } 215 DebugGetDefaultAttributeContext()216 internal AttributedModelProvider DebugGetDefaultAttributeContext() 217 { 218 return _defaultAttributeContext; 219 } 220 } 221 } 222