/// <summary> /// Determine a Model Type based on semantic mappings (and a given base model type). /// </summary> /// <param name="baseModelType">The base type as obtained from the View Model.</param> /// <returns>The given base Model Type or a subclass if a more specific class can be resolved via semantic mapping.</returns> /// <remarks> /// This method makes it possible (for example) to let the <see cref="Teaser.Media"/> property get an instance of <see cref="Image"/> /// rather than just <see cref="MediaItem"/> (the type of the View Model property). /// </remarks> public Type GetModelTypeFromSemanticMapping(Type baseModelType) { Type[] foundAmbiguousMappings = null; string[] semanticTypeNames = GetSemanticTypeNames(); foreach (string semanticTypeName in semanticTypeNames) { IEnumerable <Type> mappedModelTypes = ModelTypeRegistry.GetMappedModelTypes(semanticTypeName); if (mappedModelTypes == null) { continue; } Type[] matchingModelTypes = mappedModelTypes.Where(t => baseModelType.IsAssignableFrom(t)).ToArray(); if (matchingModelTypes.Length == 1) { // Exactly one matching model type; return it. return(matchingModelTypes[0]); } if (matchingModelTypes.Length > 1) { // Multiple candidate models types found. Continue scanning; maybe we'll find a unique one for another semantic type. foundAmbiguousMappings = matchingModelTypes; } } string errorMessage; if (foundAmbiguousMappings == null) { errorMessage = $"No semantic mapping found between Schema {Id} ({String.Join(", ", semanticTypeNames)}) and model type '{baseModelType.FullName}'"; } else { errorMessage = $"Ambiguous semantic mappings found between Schema {Id} ({String.Join(", ", semanticTypeNames)}) and model type '{String.Join(", ", foundAmbiguousMappings.Select(t => t.FullName))}'. Found types: {baseModelType.FullName}"; } if (baseModelType.IsAbstract) { // Base model type is abstract and we didn't find an (unambigous) concrete subtype to instantiate. throw new DxaException(errorMessage); } // Base model type is concrete, so we can fall back to instantiating that type. if (foundAmbiguousMappings == null) { Log.Debug("{0}. Sticking with model type.", errorMessage); } else { Log.Warn("{0}. Sticking with model type.", errorMessage); } return(baseModelType); }
/// <summary> /// Determine a Model Type based on semantic mappings (and a given base model type). /// </summary> /// <param name="baseModelType">The base type as obtained from the View Model.</param> /// <returns>The given base Model Type or a subclass if a more specific class can be resolved via semantic mapping.</returns> /// <remarks> /// This method makes it possible (for example) to let the <see cref="Teaser.Media"/> property get an instance of <see cref="Image"/> /// rather than just <see cref="MediaItem"/> (the type of the View Model property). /// </remarks> public Type GetModelTypeFromSemanticMapping(Type baseModelType) { Type[] foundAmbiguousMappings = null; string[] semanticTypeNames = GetSemanticTypeNames(); foreach (string semanticTypeName in semanticTypeNames) { IEnumerable <Type> mappedModelTypes = ModelTypeRegistry.GetMappedModelTypes(semanticTypeName); if (mappedModelTypes == null) { continue; } Type[] matchingModelTypes = mappedModelTypes.Where(t => baseModelType.IsAssignableFrom(t)).ToArray(); if (matchingModelTypes.Length == 1) { // Exactly one matching model type; return it. return(matchingModelTypes[0]); } if (matchingModelTypes.Length > 1) { // Multiple candidate models types found. Continue scanning; maybe we'll find a unique one for another semantic type. foundAmbiguousMappings = matchingModelTypes; } } if (foundAmbiguousMappings == null) { Log.Warn("No semantic mapping found between Schema {0} ({1}) and model type '{2}'. Sticking with model type.", Id, String.Join(", ", semanticTypeNames), baseModelType.FullName); } else { Log.Warn("Ambiguous semantic mappings found between Schema {0} ({1}) and model type '{2}'. Found types: {3}. Sticking with model type.", Id, String.Join(", ", semanticTypeNames), String.Join(", ", foundAmbiguousMappings.Select(t => t.FullName)), baseModelType.FullName); } return(baseModelType); }