/// <summary> /// Bind to the given model type /// </summary> /// <param name="context">Current context</param> /// <param name="modelType">Model type to bind to</param> /// <param name="instance">Optional existing instance</param> /// <param name="configuration">The <see cref="BindingConfig" /> that should be applied during binding.</param> /// <param name="blackList">Blacklisted property names</param> /// <returns>Bound model</returns> public object Bind(NancyContext context, Type modelType, object instance, BindingConfig configuration, params string[] blackList) { Type genericType = null; if (modelType.IsArray() || modelType.IsCollection() || modelType.IsEnumerable()) { //make sure it has a generic type if (modelType.IsGenericType()) { genericType = modelType.GetGenericArguments().FirstOrDefault(); } else { var implementingIEnumerableType = modelType.GetInterfaces().Where(i => i.IsGenericType()).FirstOrDefault( i => i.GetGenericTypeDefinition() == typeof (IEnumerable<>)); genericType = implementingIEnumerableType == null ? null : implementingIEnumerableType.GetGenericArguments().FirstOrDefault(); } if (genericType == null) { throw new ArgumentException("When modelType is an enumerable it must specify the type", "modelType"); } } var bindingContext = CreateBindingContext(context, modelType, instance, configuration, blackList, genericType); var bodyDeserializedModel = DeserializeRequestBody(bindingContext); return (instance as IEnumerable<string>) ?? bodyDeserializedModel; }
/// <summary> /// Convert the string representation to the destination type /// </summary> /// <param name="input">Input string</param> /// <param name="destinationType">Destination type</param> /// <param name="context">Current context</param> /// <returns>Converted object of the destination type</returns> public object Convert(string input, Type destinationType, BindingContext context) { if (string.IsNullOrEmpty(input)) { return null; } var items = input.Split(','); // Strategy, schmategy ;-) if (destinationType.IsCollection()) { return this.ConvertCollection(items, destinationType, context); } if (destinationType.IsArray()) { return this.ConvertArray(items, destinationType, context); } if (destinationType.IsEnumerable()) { return this.ConvertEnumerable(items, destinationType, context); } return null; }
/// <summary> /// Convert the string representation to the destination type /// </summary> /// <param name="input">Input string</param> /// <param name="destinationType">Destination type</param> /// <param name="context">Current context</param> /// <returns>Converted object of the destination type</returns> public object Convert(string input, Type destinationType, BindingContext context) { // TODO - Lots of reflection in here, should probably cache the methodinfos if (string.IsNullOrEmpty(input)) { return null; } var items = input.Split(','); // Strategy, schmategy ;-) if (destinationType.IsCollection()) { return this.ConvertCollection(items, destinationType, context); } if (destinationType.IsArray()) { return this.ConvertArray(items, destinationType, context); } if (destinationType.IsEnumerable()) { return this.ConvertEnumerable(items, destinationType, context); } return null; }
/// <summary> /// Bind to the given model type /// </summary> /// <param name="context">Current context</param> /// <param name="modelType">Model type to bind to</param> /// <param name="instance">Optional existing instance</param> /// <param name="configuration">The <see cref="BindingConfig"/> that should be applied during binding.</param> /// <param name="blackList">Blacklisted property names</param> /// <returns>Bound model</returns> public object Bind(NancyContext context, Type modelType, object instance, BindingConfig configuration, params string[] blackList) { Type genericType = null; if (modelType.IsArray() || modelType.IsCollection() || modelType.IsEnumerable()) { //make sure it has a generic type if (modelType.IsGenericType()) { genericType = modelType.GetGenericArguments().FirstOrDefault(); } else { var ienumerable = modelType.GetInterfaces().Where(i => i.IsGenericType()).FirstOrDefault( i => i.GetGenericTypeDefinition() == typeof(IEnumerable<>)); genericType = ienumerable == null ? null : ienumerable.GetGenericArguments().FirstOrDefault(); } if (genericType == null) { throw new ArgumentException("when modeltype is an enumerble it must specify the type", "modelType"); } } var bindingContext = this.CreateBindingContext(context, modelType, instance, configuration, blackList, genericType); var bodyDeserializedModel = this.DeserializeRequestBody(bindingContext); if (bodyDeserializedModel != null) { UpdateModelWithDeserializedModel(bodyDeserializedModel, bindingContext); } var bindingExceptions = new List<PropertyBindingException>(); if (!bindingContext.Configuration.BodyOnly) { if (bindingContext.DestinationType.IsCollection() || bindingContext.DestinationType.IsArray() || bindingContext.DestinationType.IsEnumerable()) { var loopCount = GetBindingListInstanceCount(context); var model = (IList)bindingContext.Model; for (var i = 0; i < loopCount; i++) { object genericinstance; if (model.Count > i) { genericinstance = model[i]; } else { genericinstance = Activator.CreateInstance(bindingContext.GenericType); model.Add(genericinstance); } foreach (var modelProperty in bindingContext.ValidModelProperties) { var existingCollectionValue = modelProperty.GetValue(genericinstance, null); var collectionStringValue = GetValue(modelProperty.Name, bindingContext, i); if (BindingValueIsValid(collectionStringValue, existingCollectionValue, modelProperty, bindingContext)) { try { BindProperty(modelProperty, collectionStringValue, bindingContext, genericinstance); } catch (PropertyBindingException ex) { bindingExceptions.Add(ex); } } } } } else { foreach (var modelProperty in bindingContext.ValidModelProperties) { var existingValue = modelProperty.GetValue(bindingContext.Model, null); var stringValue = GetValue(modelProperty.Name, bindingContext); if (BindingValueIsValid(stringValue, existingValue, modelProperty, bindingContext)) { try { BindProperty(modelProperty, stringValue, bindingContext); } catch (PropertyBindingException ex) { bindingExceptions.Add(ex); } } } } if (bindingExceptions.Any()) { throw new ModelBindingException(modelType, bindingExceptions); } } if (modelType.IsArray()) { var generictoArrayMethod = toArrayMethodInfo.MakeGenericMethod(new[] { genericType }); return generictoArrayMethod.Invoke(null, new[] { bindingContext.Model }); } return bindingContext.Model; }
private static object CreateModel(Type modelType, Type genericType, object instance) { if (modelType.IsArray() || modelType.IsCollection() || modelType.IsEnumerable()) { //make sure instance has a Add method. Otherwise call `.ToList` if (instance != null && modelType.IsInstanceOfType(instance)) { var addMethod = modelType.GetMethod("Add", BindingFlags.Public | BindingFlags.Instance); if (addMethod != null) { return instance; } var genericMethod = toListMethodInfo.MakeGenericMethod(genericType); return genericMethod.Invoke(null, new[] { instance }); } //else just make a list var listType = typeof(List<>).MakeGenericType(genericType); return Activator.CreateInstance(listType); } if (instance == null) { return Activator.CreateInstance(modelType); } return !modelType.IsInstanceOfType(instance) ? Activator.CreateInstance(modelType) : instance; }
/// <summary> /// Whether the converter can convert to the destination type /// </summary> /// <param name="destinationType">Destination type</param> /// <param name="context">The current binding context</param> /// <returns>True if conversion supported, false otherwise</returns> public bool CanConvertTo(Type destinationType, BindingContext context) { return destinationType.IsCollection() || destinationType.IsEnumerable() || destinationType.IsArray(); }
/// <summary> /// Bind to the given model type /// </summary> /// <param name="obj">object to be converted into a model</param> /// <param name="modelType">Model type to bind to</param> /// <param name="blackList">Blacklisted binding property names</param> /// <returns>Bound model</returns> public virtual object Bind(object obj, Type modelType) { if(obj == null) { return null; } Type genericType = null; if (modelType.IsCollectionOrArray()) { //make sure it has a generic type if (modelType.GetTypeInfo().IsGenericType) { genericType = modelType.GetGenericArguments().FirstOrDefault(); } else { var ienumerable = modelType.GetInterfaces().Where(i => i.GetTypeInfo().IsGenericType).FirstOrDefault(i => i.GetGenericTypeDefinition() == typeof(IEnumerable<>)); genericType = ienumerable == null ? null : ienumerable.GetGenericArguments().FirstOrDefault(); } if (genericType == null) { throw new ArgumentException("When modelType is an enumerable it must specify the type.", "modelType"); } } var bindingContext = this.CreateBindingContext(obj, modelType, genericType); if (bindingContext.DestinationType.IsCollectionOrArray()) { var model = (IList)bindingContext.Model; var collection = obj as ICollection; if(collection == null) { return null; } for (var i = 0; i < collection.Count; i++) { var val = GetValue(bindingContext, i); if (val != null) { if (val.GetType() == typeof(Dictionary<string, object>)) { var subModel = Bind(val, genericType); model.Add(subModel); } else { model.Add(val); } } } } else { foreach (var modelProperty in bindingContext.ValidModelBindingMembers) { var val = GetValue(modelProperty.Name, bindingContext); if (val != null) { BindValue(modelProperty, val, bindingContext); } } } if (modelType.IsArray()) { var generictoArrayMethod = ToArrayMethodInfo.MakeGenericMethod(new[] { genericType }); return generictoArrayMethod.Invoke(null, new[] { bindingContext.Model }); } return bindingContext.Model; }