/// <summary> /// Creates a new type of error model depending on the errors in the the dictionary. /// </summary> /// <param name="dict">A dictionary where each key (property name) has a list of error messages related to that key</param> /// <param name="dynamicFactory">A dynamic factory for creating new types</param> /// <returns>A instance of the new created type</returns> public static object GetModelError(this Dictionary <string, List <string> > dict, DynamicTypeFactory dynamicFactory) { List <DynamicProperty> dynamicProperties = new List <DynamicProperty>(); foreach (var key in dict.Keys) { dynamicProperties.Add(new DynamicProperty { DisplayName = key.ToCamelCase(), PropertyName = key.ToCamelCase(), SystemTypeName = dict[key].Count > 1 ? typeof(List <string>).ToString() : typeof(string).ToString() }); } var errorType = dynamicFactory.CreateNewTypeWithDynamicProperties(typeof(ErrorModel), dynamicProperties); var errorObject = Activator.CreateInstance(errorType); foreach (var key in dict.Keys) { dynamic value; if (dict[key].Count > 1) { value = dict[key]; } else { value = dict[key][0]; } errorType.GetProperty($"{key.ToCamelCase()}") .SetValue(errorObject, value); } return(errorObject); }
/// <summary> /// The main entry point for the application. /// </summary> /// <param name="args">The command-line arguments passed to the program</param> static void Main(string[] args) { // Read the todos, dynamic property definitions and values from the JSON content files. var todos = JsonSerializer.Deserialize <IList <Todo> >(File.ReadAllText(@"Content\todos.json")); var dynamicProperties = JsonSerializer.Deserialize <IList <DynamicProperty> >(File.ReadAllText(@"Content\dynamic-properties.json")); var dynamicTodoValues = JsonSerializer.Deserialize <IList <TodoDynamicValue> >(File.ReadAllText(@"Content\todo-dynamic-values.json")); // Create a new Type based on a 'Todo' with additional dynamic properties. var factory = new DynamicTypeFactory(); var extendedType = factory.CreateNewTypeWithDynamicProperties(typeof(Todo), dynamicProperties); // Get all read/write properties for the extended Type. var properties = extendedType.GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.CanRead && p.CanWrite); // Populate a list of objects of the extended Type and display the property names and values. object extendedObject = null; for (int i = 0; i < todos.Count(); i++) { extendedObject = Activator.CreateInstance(extendedType); string todoHeading = $"Todo {i + 1}"; Console.WriteLine(todoHeading); Console.WriteLine("".PadLeft(todoHeading.Length, '=')); Console.WriteLine(); extendedType.GetProperty($"{nameof(Todo.Id)}") .SetValue(extendedObject, todos[i].Id, null); extendedType.GetProperty($"{nameof(Todo.UserId)}") .SetValue(extendedObject, todos[i].UserId, null); extendedType.GetProperty($"{nameof(Todo.Title)}") .SetValue(extendedObject, todos[i].Title, null); extendedType.GetProperty($"{nameof(Todo.Completed)}") .SetValue(extendedObject, todos[i].Completed, null); // NOTE: The dynamic property names are prefixed to mitigate against name collision. extendedType.GetProperty($"{nameof(DynamicProperty)}_{nameof(TodoDynamicValue.Important)}") .SetValue(extendedObject, dynamicTodoValues[i].Important, null); extendedType.GetProperty($"{nameof(DynamicProperty)}_{nameof(TodoDynamicValue.Notes)}") .SetValue(extendedObject, dynamicTodoValues[i].Notes, null); foreach (PropertyInfo property in properties) { Console.WriteLine($"{property.Name}: {property.GetValue(extendedObject, null)}"); } Console.WriteLine(); } Console.ReadKey(); }
/// <summary> /// Creates a new type of error model depending on the errors in the the model state. /// </summary> /// <param name="modelState">A model state dictionary where each key (property name) has a list of error messages related to that key</param> /// <param name="dynamicFactory">A dynamic factory for creating new types</param> /// <returns>A instance of the new created type</returns> public static object GetErrors(this ModelStateDictionary modelState, DynamicTypeFactory dynamicFactory) { List <DynamicProperty> dynamicProperties = new List <DynamicProperty>(); foreach (var key in modelState.Keys) { dynamicProperties.Add(new DynamicProperty { DisplayName = key.ToCamelCase(), PropertyName = key.ToCamelCase(), SystemTypeName = modelState[key].Errors.Count > 1 ? typeof(List <string>).ToString() : typeof(string).ToString() }); } var errorType = dynamicFactory.CreateNewTypeWithDynamicProperties(typeof(ErrorModel), dynamicProperties); var errorObject = Activator.CreateInstance(errorType); foreach (var key in modelState.Keys) { List <string> errors = new List <string>(); foreach (var error in modelState[key].Errors) { errors.Add(error.ErrorMessage); } dynamic value; if (errors.Count > 1) { value = errors; } else { value = errors[0]; } errorType.GetProperty($"{key.ToCamelCase()}") .SetValue(errorObject, value); } return(errorObject); }