// /// <summary> /// Creates a new <see cref="ModelMappingDictionary"/> for an object model type. /// </summary> /// <param name="modelType">The type of object model to read property mappings from.</param> /// <returns>A new, filled instance.</returns> public static ModelMappingDictionary CreateFrom(Type modelType) { if (modelType == null) { throw new ArgumentNullException(nameof(modelType)); } var modelMappingDictionary = new ModelMappingDictionary(modelType); foreach (var mapping in GetModelMappingsForPropertiesOfType(modelType)) { modelMappingDictionary.Add(mapping.SourceKeyName, mapping); } return(modelMappingDictionary); }
/// <summary> /// Reads the current appSettings section into a new instance of the model class type specified. /// </summary> /// <param name="modelType">Type of the model.</param> /// <param name="errors">When an errors collection is supplied, then throwing is suppressed and instead the errors collection is populated.</param> /// <returns> /// An instance of the type specified. /// </returns> /// <exception cref="ArgumentNullException">modelType</exception> /// <exception cref="Evoq.Configuration.InvalidConfigurationModelException"> /// </exception> /// <exception cref="InvalidConfigurationModelException"></exception> public object ReadInto(Type modelType, ICollection <ConfigurationModelValidationError> errors) { if (modelType == null) { throw new ArgumentNullException(nameof(modelType)); } bool throwOnValidationErrors = (errors == null); // If we were not supplied with a bucket in which to stick errors, we must throw. var modelMappings = ModelMappingDictionary.CreateFrom(modelType); if (modelMappings.Any()) { object model; model = this.CreateModelInstanceOrThrow(modelType); foreach (var mapping in modelMappings.Values) { try { // SetValue will throw given the wrong type for the model property. object sourceValue = this.GetSourceValue(mapping); mapping.PropertyInfo.SetValue(model, sourceValue); } catch (InvalidOperationException notValidException) when(notValidException.Message.Contains("not a valid")) { // Invalid type cast/convert. if (throwOnValidationErrors) { throw new InvalidConfigurationModelException($"Cannot read the settings into {modelType.Name}.{mapping.ModelPropertyName}. {notValidException.Message}", notValidException); } else { errors.Add(new ConfigurationModelValidationError(notValidException.Message, new string[] { mapping.ModelPropertyName })); } } catch (KeyNotFoundException) { // Missing. We can swallow the problem here and allow later validation step to deal with it. } catch (InvalidOperationException) { // Missing. We can swallow the problem here and allow later validation step to deal with it. } } IEnumerable <ConfigurationModelValidationError> validationErrors = null; bool isValid = this.ModelValidator.TryValidateModel(model, out validationErrors); if (!isValid) { // Invalid. if (throwOnValidationErrors) { string message; if (validationErrors.Count() == 1) { message = $"Cannot read the settings into {modelType.Name}. {validationErrors.First().ErrorMessage}"; } else { message = $"Cannot read the settings into {modelType.Name}. There are {validationErrors.Count()} validation errors."; } throw new InvalidConfigurationModelException(message) { ValidationErrors = validationErrors }; } else { foreach (var error in validationErrors) { errors.Add(error); } } } return(model); } else { throw new InvalidConfigurationModelException($"Cannot read the appSettings section. The model class {modelType.Name} has no public properties."); } }