public bool IsPartDiscoverable() { // The part should not be marked with the "NonDiscoverable" if (_type.IsAttributeDefined <PartNotDiscoverableAttribute>()) { CompositionTrace.DefinitionMarkedWithPartNotDiscoverableAttribute(_type); return(false); } // The part should have exports if (!HasExports()) { CompositionTrace.DefinitionContainsNoExports(_type); return(false); } // If the part is generic, all exports should have the same number of generic parameters // (otherwise we have no way to specialize the part based on an export) if (!AllExportsHaveMatchingArity()) { // The function has already reported all violations via tracing return(false); } return(true); }
private AssemblyCatalog?CreateAssemblyCatalogGuarded(string assemblyFilePath) { Exception?exception = null; try { return((_reflectionContext != null) ? new AssemblyCatalog(assemblyFilePath, _reflectionContext, this) : new AssemblyCatalog(assemblyFilePath, this)); } catch (FileNotFoundException ex) { // Files should always exists but don't blow up here if they don't exception = ex; } catch (FileLoadException ex) { // File was found but could not be loaded exception = ex; } catch (BadImageFormatException ex) { // Dlls that contain native code are not loaded, but do not invalidate the Directory exception = ex; } catch (ReflectionTypeLoadException ex) { // Dlls that have missing Managed dependencies are not loaded, but do not invalidate the Directory exception = ex; } CompositionTrace.AssemblyLoadFailed(this, assemblyFilePath, exception); return(null); }
private static void ConfigureConstructorAttributes(ConstructorInfo constructorInfo, ref List <Tuple <object, List <Attribute> > > configuredMembers, Action <ParameterInfo, ImportBuilder> configureConstuctorImports) { if (configuredMembers == null) { configuredMembers = new List <Tuple <object, List <Attribute> > >(); } // Make its attribute configuredMembers.Add(Tuple.Create((object)constructorInfo, s_importingConstructorList)); //Okay we have the constructor now we can configure the ImportBuilders ParameterInfo[] parameterInfos = constructorInfo.GetParameters(); foreach (ParameterInfo pi in parameterInfos) { bool isConfigured = pi.GetCustomAttributes(typeof(ImportAttribute), false).FirstOrDefault() != null || pi.GetCustomAttributes(typeof(ImportManyAttribute), false).FirstOrDefault() != null; if (isConfigured) { CompositionTrace.Registration_ParameterImportConventionOverridden(pi, constructorInfo); } else { var importBuilder = new ImportBuilder(); // Let the developer alter them if they specified to do so configureConstuctorImports?.Invoke(pi, importBuilder); // Generate the attributes List <Attribute> attributes = null; importBuilder.BuildAttributes(pi.ParameterType, ref attributes); configuredMembers.Add(Tuple.Create((object)pi, attributes)); } } }
private bool AllExportsHaveMatchingArity() { bool isArityMatched = true; if (_type.ContainsGenericParameters) { int partGenericArity = _type.GetPureGenericArity(); // each member should have the same arity foreach (MemberInfo member in GetExportMembers(_type).Concat(GetInheritedExports(_type))) { if (member.MemberType == MemberTypes.Method) { // open generics are unsupported on methods if (((MethodInfo)member).ContainsGenericParameters) { isArityMatched = false; CompositionTrace.DefinitionMismatchedExportArity(_type, member); continue; } } if (member.GetDefaultTypeFromMember().GetPureGenericArity() != partGenericArity) { isArityMatched = false; CompositionTrace.DefinitionMismatchedExportArity(_type, member); } } } return(isArityMatched); }
internal void BuildOnImportsSatisfiedNotification(Type type, ref List <Tuple <object, List <Attribute> > > configuredMembers) { //Add OnImportsSatisfiedAttribute where specified if (_methodImportsSatisfiedNotifications != null) { foreach (MethodInfo mi in type.GetRuntimeMethods()) { //We are only interested in void methods with no arguments if (mi.ReturnParameter.ParameterType == typeof(void) && mi.GetParameters().Length == 0) { MethodInfo underlyingMi = mi.DeclaringType.GetRuntimeMethod(mi.Name, _emptyTypeArray); if (underlyingMi != null) { bool checkedIfConfigured = false; bool isConfigured = false; foreach (Predicate <MethodInfo> notification in _methodImportsSatisfiedNotifications) { if (notification(underlyingMi)) { if (!checkedIfConfigured) { isConfigured = mi.GetCustomAttributes <OnImportsSatisfiedAttribute>(false).FirstOrDefault() != null; checkedIfConfigured = true; } if (isConfigured) { CompositionTrace.Registration_OnSatisfiedImportNotificationOverridden(type, mi); break; } else { // We really only need to create this list once and then cache it, it never goes back to null // Its perfectly okay if we make a list a few times on different threads, effectively though once we have // cached one we will never make another. if (s_onImportsSatisfiedAttributeList == null) { var onImportsSatisfiedAttributeList = new List <Attribute> { new OnImportsSatisfiedAttribute() }; s_onImportsSatisfiedAttributeList = onImportsSatisfiedAttributeList; } configuredMembers.Add(new Tuple <object, List <Attribute> >(mi, s_onImportsSatisfiedAttributeList)); } } } } } } } }
public bool IsPartDiscoverable() { if (this._type.IsAttributeDefined <PartNotDiscoverableAttribute>()) { CompositionTrace.DefinitionMarkedWithPartNotDiscoverableAttribute(this._type); return(false); } if (!HasExports()) { CompositionTrace.DefinitionContainsNoExports(this._type); return(false); } return(true); }
private static IAttributedImport GetAttributedImport(ReflectionItem item, ICustomAttributeProvider attributeProvider) { IAttributedImport[] imports = attributeProvider.GetAttributes <IAttributedImport>(false); // For constructor parameters they may not have an ImportAttribute if (imports.Length == 0) { return(new ImportAttribute()); } if (imports.Length > 1) { CompositionTrace.MemberMarkedWithMultipleImportAndImportMany(item); } // Regardless of how many imports, always return the first one return(imports[0]); }
internal bool BuildConstructorAttributes(Type type, ref List <Tuple <object, List <Attribute> > > configuredMembers) { IEnumerable <ConstructorInfo> constructors = type.GetTypeInfo().DeclaredConstructors; // First see if any of these constructors have the ImportingConstructorAttribute if so then we are already done foreach (var ci in constructors) { // We have a constructor configuration we must log a warning then not bother with ConstructorAttributes #if netstandard10 IEnumerable <Attribute> attributes = ci.GetCustomAttributes(typeof(ImportingConstructorAttribute), false); #else IEnumerable <Attribute> attributes = Attribute.GetCustomAttributes(ci, typeof(ImportingConstructorAttribute), false); #endif if (attributes.Count() != 0) { CompositionTrace.Registration_ConstructorConventionOverridden(type); return(true); } } if (_constructorFilter != null) { ConstructorInfo constructorInfo = _constructorFilter(constructors); if (constructorInfo != null) { ConfigureConstructorAttributes(constructorInfo, ref configuredMembers, _configureConstuctorImports); } return(true); } else if (_configureConstuctorImports != null) { bool configured = false; foreach (var constructorInfo in FindLongestConstructors(constructors)) { ConfigureConstructorAttributes(constructorInfo, ref configuredMembers, _configureConstuctorImports); configured = true; } return(configured); } return(false); }
internal bool BuildConstructorAttributes(Type type, ref List <Tuple <object, List <Attribute> > > configuredMembers) { ConstructorInfo[] constructors = type.GetConstructors(); // First see if any of these constructors have the ImportingConstructorAttribute if so then we are already done foreach (ConstructorInfo ci in constructors) { // We have a constructor configuration we must log a warning then not bother with ConstructorAttributes object[] attributes = ci.GetCustomAttributes(typeof(ImportingConstructorAttribute), false); if (attributes.Length != 0) { CompositionTrace.Registration_ConstructorConventionOverridden(type); return(true); } } if (_constructorFilter != null) { ConstructorInfo constructorInfo = _constructorFilter(constructors); if (constructorInfo != null) { ConfigureConstructorAttributes(constructorInfo, ref configuredMembers, _configureConstuctorImports); } return(true); } else if (_configureConstuctorImports != null) { bool configured = false; foreach (ConstructorInfo constructorInfo in FindLongestConstructors(constructors)) { ConfigureConstructorAttributes(constructorInfo, ref configuredMembers, _configureConstuctorImports); configured = true; } return(configured); } return(false); }
private void UpdateRejections(IEnumerable <ExportDefinition> changedExports, AtomicComposition atomicComposition) { using (var localAtomicComposition = new AtomicComposition(atomicComposition)) { // Reconsider every part definition that has been previously // rejected to see if any of them can be added back. var affectedRejections = new HashSet <ComposablePartDefinition>(); ComposablePartDefinition[] rejectedParts; using (_lock.LockStateForRead()) { rejectedParts = _rejectedParts.ToArray(); } foreach (var definition in rejectedParts) { if (QueryPartState(localAtomicComposition, definition) == AtomicCompositionQueryState.TreatAsValidated) { continue; } foreach (var import in definition.ImportDefinitions.Where(ImportEngine.IsRequiredImportForPreview)) { if (changedExports.Any(export => import.IsConstraintSatisfiedBy(export))) { affectedRejections.Add(definition); break; } } } UpdateAtomicCompositionQueryForPartInHashSet(localAtomicComposition, affectedRejections, AtomicCompositionQueryState.NeedsTesting); // Determine if any of the resurrectable parts is now available so that we can // notify listeners of the exact changes to exports var resurrectedExports = new List <ExportDefinition>(); foreach (var partDefinition in affectedRejections) { if (!IsRejected(partDefinition, localAtomicComposition)) { // Notify listeners of the newly available exports and // prepare to remove the rejected part from the list of rejections resurrectedExports.AddRange(partDefinition.ExportDefinitions); // Capture the local so that the closure below refers to the current definition // in the loop and not the value of 'partDefinition' when the closure executes var capturedPartDefinition = partDefinition; localAtomicComposition.AddCompleteAction(() => { using (_lock.LockStateForWrite()) { _rejectedParts.Remove(capturedPartDefinition); } CompositionTrace.PartDefinitionResurrected(capturedPartDefinition); }); } } // Notify anyone sourcing exports that the resurrected exports have appeared if (resurrectedExports.Any()) { OnExportsChanging( new ExportsChangeEventArgs(resurrectedExports, Array.Empty <ExportDefinition>(), localAtomicComposition)); localAtomicComposition.AddCompleteAction(() => OnExportsChanged( new ExportsChangeEventArgs(resurrectedExports, Array.Empty <ExportDefinition>(), null))); } localAtomicComposition.Complete(); } }
private bool DetermineRejection(ComposablePartDefinition definition, AtomicComposition parentAtomicComposition) { ChangeRejectedException exception = null; // if there is no active atomic composition and rejection is disabled, there's no need to do any of the below if (!EnsureRejection(parentAtomicComposition)) { return(false); } using (var localAtomicComposition = new AtomicComposition(parentAtomicComposition)) { // The part definition we're currently working on is treated optimistically // as if we know it hasn't been rejected. This handles recursion, and if we // later decide that it has been rejected we'll discard all nested progress so // all side-effects of the mistake are erased. // // Note that this means that recursive failures that would be detected by the // import engine are not discovered by rejection currently. Loops among // prerequisites, runaway import chains involving factories, and prerequisites // that cannot be fully satisfied still result in runtime errors. Doing // otherwise would be possible but potentially expensive - and could be a v2 // improvement if deemed worthwhile. UpdateAtomicCompositionQueryForPartEquals(localAtomicComposition, definition, AtomicCompositionQueryState.TreatAsValidated); var newPart = definition.CreatePart(); try { _importEngine.PreviewImports(newPart, localAtomicComposition); // Reuse the partially-fleshed out part the next time we need a shared // instance to keep the expense of pre-validation to a minimum. Note that // _activatedParts holds references to both shared and non-shared parts. // The non-shared parts will only be used for rejection purposes only but // the shared parts will be handed out when requested via GetExports as // well as be used for rejection purposes. localAtomicComposition.AddCompleteActionAllowNull(() => { using (_lock.LockStateForWrite()) { if (!_activatedParts.ContainsKey(definition)) { _activatedParts.Add(definition, new CatalogPart(newPart)); IDisposable newDisposablePart = newPart as IDisposable; if (newDisposablePart != null) { _partsToDispose.Add(newDisposablePart); } } } }); // Success! Complete any recursive work that was conditioned on this part's validation localAtomicComposition.Complete(); return(false); } catch (ChangeRejectedException ex) { exception = ex; } } // If we've reached this point then this part has been rejected so we need to // record the rejection in our parent composition or execute it immediately if // one doesn't exist. parentAtomicComposition.AddCompleteActionAllowNull(() => { using (_lock.LockStateForWrite()) { _rejectedParts.Add(definition); } CompositionTrace.PartDefinitionRejected(definition, exception); }); if (parentAtomicComposition != null) { UpdateAtomicCompositionQueryForPartEquals(parentAtomicComposition, definition, AtomicCompositionQueryState.TreatAsRejected); } return(true); }
internal void BuildPropertyAttributes(Type type, ref List <Tuple <object, List <Attribute> > > configuredMembers) { if (this._propertyImports.Any() || this._propertyExports.Any()) { foreach (var pi in type.GetRuntimeProperties()) { List <Attribute> attributes = null; int importsBuilt = 0; bool checkedIfConfigured = false; bool isConfigured = false; PropertyInfo underlyingPi = null; // Run through the import specifications see if any match foreach (var importSpecification in this._propertyImports) { if (underlyingPi == null) { underlyingPi = pi.DeclaringType.GetRuntimeProperty(pi.Name); } if (importSpecification.Item1 != null && importSpecification.Item1(underlyingPi)) { var importBuilder = new ImportConventionBuilder(); if (importSpecification.Item2 != null) { importSpecification.Item2(pi, importBuilder); } if (!checkedIfConfigured) { isConfigured = pi.GetFirstAttribute <ImportAttribute>() != null || pi.GetFirstAttribute <ImportManyAttribute>() != null; checkedIfConfigured = true; } if (isConfigured) { CompositionTrace.Registration_MemberImportConventionOverridden(type, pi); break; } else { importBuilder.BuildAttributes(pi.PropertyType, ref attributes); ++importsBuilt; } } if (importsBuilt > 1) { CompositionTrace.Registration_MemberImportConventionMatchedTwice(type, pi); } } checkedIfConfigured = false; isConfigured = false; // Run through the export specifications see if any match foreach (var exportSpecification in this._propertyExports) { if (underlyingPi == null) { underlyingPi = pi.DeclaringType.GetRuntimeProperty(pi.Name); } if (exportSpecification.Item1 != null && exportSpecification.Item1(underlyingPi)) { var exportBuilder = new ExportConventionBuilder(); if (exportSpecification.Item3 != null) { exportBuilder.AsContractType(exportSpecification.Item3); } if (exportSpecification.Item2 != null) { exportSpecification.Item2(pi, exportBuilder); } if (!checkedIfConfigured) { isConfigured = pi.GetFirstAttribute <ExportAttribute>() != null || MemberHasExportMetadata(pi); checkedIfConfigured = true; } if (isConfigured) { CompositionTrace.Registration_MemberExportConventionOverridden(type, pi); break; } else { exportBuilder.BuildAttributes(pi.PropertyType, ref attributes); } } } if (attributes != null) { if (configuredMembers == null) { configuredMembers = new List <Tuple <object, List <Attribute> > >(); } configuredMembers.Add(Tuple.Create((object)pi, attributes)); } } } return; }
internal IEnumerable <Attribute> BuildTypeAttributes(Type type) { var attributes = new List <Attribute>(); if (this._typeExportBuilders != null) { bool isConfigured = type.GetTypeInfo().GetFirstAttribute <ExportAttribute>() != null || MemberHasExportMetadata(type.GetTypeInfo()); if (isConfigured) { CompositionTrace.Registration_TypeExportConventionOverridden(type); } else { foreach (var export in this._typeExportBuilders) { export.BuildAttributes(type, ref attributes); } } } if (this._isShared) { // Check if there is already a SharedAttribute. If found Trace a warning and do not add this Shared // otherwise add new one bool isConfigured = type.GetTypeInfo().GetFirstAttribute <SharedAttribute>() != null; if (isConfigured) { CompositionTrace.Registration_PartCreationConventionOverridden(type); } else { attributes.Add(this._sharingBoundary == null ? new SharedAttribute() : new SharedAttribute(this._sharingBoundary)); } } //Add metadata attributes from direct specification if (this._metadataItems != null) { bool isConfigured = type.GetTypeInfo().GetFirstAttribute <PartMetadataAttribute>() != null; if (isConfigured) { CompositionTrace.Registration_PartMetadataConventionOverridden(type); } else { foreach (var item in this._metadataItems) { attributes.Add(new PartMetadataAttribute(item.Item1, item.Item2)); } } } //Add metadata attributes from func specification if (this._metadataItemFuncs != null) { bool isConfigured = type.GetTypeInfo().GetFirstAttribute <PartMetadataAttribute>() != null; if (isConfigured) { CompositionTrace.Registration_PartMetadataConventionOverridden(type); } else { foreach (var item in this._metadataItemFuncs) { var name = item.Item1; var value = (item.Item2 != null) ? item.Item2(type) : null; attributes.Add(new PartMetadataAttribute(name, value)); } } } if (this._interfaceExports.Any()) { if (this._typeExportBuilders != null) { bool isConfigured = type.GetTypeInfo().GetFirstAttribute <ExportAttribute>() != null || MemberHasExportMetadata(type.GetTypeInfo()); if (isConfigured) { CompositionTrace.Registration_TypeExportConventionOverridden(type); } else { foreach (var iface in type.GetTypeInfo().ImplementedInterfaces) { if (iface == typeof(IDisposable)) { continue; } // Run through the export specifications see if any match foreach (var exportSpecification in this._interfaceExports) { if (exportSpecification.Item1 != null && exportSpecification.Item1(iface)) { ExportConventionBuilder exportBuilder = new ExportConventionBuilder(); exportBuilder.AsContractType(iface); if (exportSpecification.Item2 != null) { exportSpecification.Item2(iface, exportBuilder); } exportBuilder.BuildAttributes(iface, ref attributes); } } } } } } return(attributes); }
internal void BuildPropertyAttributes(Type type, ref List <Tuple <object, List <Attribute> > > configuredMembers) { if (_propertyImports.Any() || _propertyExports.Any()) { foreach (PropertyInfo pi in type.GetProperties()) { List <Attribute> attributes = null; PropertyInfo declaredPi = pi.DeclaringType.UnderlyingSystemType.GetProperty(pi.Name, pi.PropertyType); int importsBuilt = 0; bool checkedIfConfigured = false; bool isConfigured = false; // Run through the import specifications see if any match foreach (Tuple <Predicate <PropertyInfo>, Action <PropertyInfo, ImportBuilder>, Type> importSpecification in _propertyImports) { if (importSpecification.Item1 != null && importSpecification.Item1(declaredPi)) { var importBuilder = new ImportBuilder(); if (importSpecification.Item3 != null) { importBuilder.AsContractType(importSpecification.Item3); } importSpecification.Item2?.Invoke(declaredPi, importBuilder); if (!checkedIfConfigured) { isConfigured = pi.GetCustomAttributes(typeof(ImportAttribute), false).FirstOrDefault() != null || pi.GetCustomAttributes(typeof(ImportManyAttribute), false).FirstOrDefault() != null; checkedIfConfigured = true; } if (isConfigured) { CompositionTrace.Registration_MemberImportConventionOverridden(type, pi); break; } else { importBuilder.BuildAttributes(declaredPi.PropertyType, ref attributes); ++importsBuilt; } } if (importsBuilt > 1) { CompositionTrace.Registration_MemberImportConventionMatchedTwice(type, pi); } } checkedIfConfigured = false; isConfigured = false; // Run through the export specifications see if any match foreach (Tuple <Predicate <PropertyInfo>, Action <PropertyInfo, ExportBuilder>, Type> exportSpecification in _propertyExports) { if (exportSpecification.Item1 != null && exportSpecification.Item1(declaredPi)) { var exportBuilder = new ExportBuilder(); if (exportSpecification.Item3 != null) { exportBuilder.AsContractType(exportSpecification.Item3); } exportSpecification.Item2?.Invoke(declaredPi, exportBuilder); if (!checkedIfConfigured) { isConfigured = pi.GetCustomAttributes(typeof(ExportAttribute), false).FirstOrDefault() != null || MemberHasExportMetadata(pi); checkedIfConfigured = true; } if (isConfigured) { CompositionTrace.Registration_MemberExportConventionOverridden(type, pi); break; } else { exportBuilder.BuildAttributes(declaredPi.PropertyType, ref attributes); } } } if (attributes != null) { if (configuredMembers == null) { configuredMembers = new List <Tuple <object, List <Attribute> > >(); } configuredMembers.Add(Tuple.Create((object)declaredPi, attributes)); } } } }
internal IEnumerable <Attribute> BuildTypeAttributes(Type type) { var attributes = new List <Attribute>(); if (_typeExportBuilders != null) { bool isConfigured = type.GetCustomAttributes(typeof(ExportAttribute), false).FirstOrDefault() != null || MemberHasExportMetadata(type); if (isConfigured) { CompositionTrace.Registration_TypeExportConventionOverridden(type); } else { foreach (ExportBuilder export in _typeExportBuilders) { export.BuildAttributes(type, ref attributes); } } } if (_setCreationPolicy) { // Check if there is already a PartCreationPolicyAttribute // If found Trace a warning and do not add the registered part creationpolicy // otherwise add new one bool isConfigured = type.GetCustomAttributes(typeof(PartCreationPolicyAttribute), false).FirstOrDefault() != null; if (isConfigured) { CompositionTrace.Registration_PartCreationConventionOverridden(type); } else { attributes.Add(new PartCreationPolicyAttribute(_creationPolicy)); } } //Add metadata attributes from direct specification if (_metadataItems != null) { bool isConfigured = type.GetCustomAttributes(typeof(PartMetadataAttribute), false).FirstOrDefault() != null; if (isConfigured) { CompositionTrace.Registration_PartMetadataConventionOverridden(type); } else { foreach (Tuple <string, object> item in _metadataItems) { attributes.Add(new PartMetadataAttribute(item.Item1, item.Item2)); } } } //Add metadata attributes from func specification if (_metadataItemFuncs != null) { bool isConfigured = type.GetCustomAttributes(typeof(PartMetadataAttribute), false).FirstOrDefault() != null; if (isConfigured) { CompositionTrace.Registration_PartMetadataConventionOverridden(type); } else { foreach (Tuple <string, Func <Type, object> > item in _metadataItemFuncs) { var name = item.Item1; var value = (item.Item2 != null) ? item.Item2(type) : null; attributes.Add(new PartMetadataAttribute(name, value)); } } } if (_interfaceExports.Any()) { if (_typeExportBuilders != null) { bool isConfigured = type.GetCustomAttributes(typeof(ExportAttribute), false).FirstOrDefault() != null || MemberHasExportMetadata(type); if (isConfigured) { CompositionTrace.Registration_TypeExportConventionOverridden(type); } else { foreach (Type iface in type.GetInterfaces()) { Type underlyingType = iface.UnderlyingSystemType; if (underlyingType == typeof(IDisposable) || underlyingType == typeof(IPartImportsSatisfiedNotification)) { continue; } // Run through the export specifications see if any match foreach (Tuple <Predicate <Type>, Action <Type, ExportBuilder> > exportSpecification in _interfaceExports) { if (exportSpecification.Item1 != null && exportSpecification.Item1(underlyingType)) { ExportBuilder exportBuilder = new ExportBuilder(); exportBuilder.AsContractType((Type)iface); exportSpecification.Item2?.Invoke(iface, exportBuilder); exportBuilder.BuildAttributes(iface, ref attributes); } } } } } } return(attributes); }