public void CreateOrReplaceCollection_OriginalModelMutable_UpdatesOriginalInstance()
        {
            // Arrange
            List <int> originalInstance = new List <int> {
                10, 20, 30
            };
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext
            {
                ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(
                    () => originalInstance,
                    typeof(ICollection <int>)
                    )
            };

            // Act
            CollectionModelBinderUtil.CreateOrReplaceCollection(
                bindingContext,
                new[] { 40, 50, 60 },
                () => new List <int>()
                );

            // Assert
            Assert.Same(originalInstance, bindingContext.Model);
            Assert.Equal(new[] { 40, 50, 60 }, originalInstance.ToArray());
        }
Пример #2
0
        public void CreateOrReplaceDictionary_OriginalModelMutable_UpdatesOriginalInstance()
        {
            // Arrange
            Dictionary <string, string> originalInstance = new Dictionary <string, string>
            {
                { "dog", "Canidae" },
                { "cat", "Felidae" }
            };
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext
            {
                ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => originalInstance, typeof(IDictionary <string, string>))
            };

            // Act
            CollectionModelBinderUtil.CreateOrReplaceDictionary(
                bindingContext,
                new Dictionary <string, string>
            {
                { "horse", "Equidae" },
                { "bear", "Ursidae" }
            },
                () => new Dictionary <string, string>());

            // Assert
            Assert.Same(originalInstance, bindingContext.Model);
            Assert.Equal(new[] { "horse", "bear" }, originalInstance.Keys.ToArray());
            Assert.Equal("Equidae", originalInstance["horse"]);
            Assert.Equal("Ursidae", originalInstance["bear"]);
        }
Пример #3
0
        public void CreateOrReplaceDictionary_OriginalModelNotDictionary_CreatesNewInstance()
        {
            // Arrange
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext
            {
                ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(IDictionary <string, string>))
            };

            // Act
            CollectionModelBinderUtil.CreateOrReplaceDictionary(
                bindingContext,
                new Dictionary <string, string>
            {
                { "horse", "Equidae" },
                { "bear", "Ursidae" }
            },
                () => new Dictionary <string, string>());

            // Assert
            IDictionary <string, string> newModel = bindingContext.Model as IDictionary <string, string>;

            Assert.Equal(new[] { "horse", "bear" }, newModel.Keys.ToArray());
            Assert.Equal("Equidae", newModel["horse"]);
            Assert.Equal("Ursidae", newModel["bear"]);
        }
Пример #4
0
        public void CreateOrReplaceDictionary_DisallowsDuplicateKeys()
        {
            // Arrange
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext
            {
                ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(Dictionary <string, int>))
            };

            // Act
            CollectionModelBinderUtil.CreateOrReplaceDictionary(
                bindingContext,
                new[]
            {
                new KeyValuePair <string, int>("forty-two", 40),
                new KeyValuePair <string, int>("forty-two", 2),
                new KeyValuePair <string, int>("forty-two", 42)
            },
                () => new Dictionary <string, int>());

            // Assert
            IDictionary <string, int> newModel = bindingContext.Model as IDictionary <string, int>;

            Assert.Equal(new[] { "forty-two" }, newModel.Keys.ToArray());
            Assert.Equal(42, newModel["forty-two"]);
        }
Пример #5
0
        public void CreateOrReplaceDictionary_OriginalModelImmutable_CreatesNewInstance()
        {
            // Arrange
            ReadOnlyDictionary <string, string> originalModel = new ReadOnlyDictionary <string, string>();

            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext
            {
                ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => originalModel, typeof(IDictionary <string, string>))
            };

            // Act
            CollectionModelBinderUtil.CreateOrReplaceDictionary(
                bindingContext,
                new Dictionary <string, string>
            {
                { "Hello", "World" }
            },
                () => new Dictionary <string, string>());

            // Assert
            IDictionary <string, string> newModel = bindingContext.Model as IDictionary <string, string>;

            Assert.NotSame(originalModel, newModel);
            Assert.Equal(new[] { "Hello" }, newModel.Keys.ToArray());
            Assert.Equal("World", newModel["Hello"]);
        }
Пример #6
0
        public void GetZeroBasedIndexes()
        {
            // Act
            string[] indexes = CollectionModelBinderUtil.GetZeroBasedIndexes().Take(5).ToArray();

            // Assert
            Assert.Equal(new[] { "0", "1", "2", "3", "4" }, indexes);
        }
        // Used when the ValueProvider contains the collection to be bound as multiple elements, e.g. foo[0], foo[1].
        private static List <TElement> BindComplexCollection(HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            string indexPropertyName = ModelBindingHelper.CreatePropertyModelName(bindingContext.ModelName, "index");
            ValueProviderResult  valueProviderResultIndex = bindingContext.ValueProvider.GetValue(indexPropertyName);
            IEnumerable <string> indexNames = CollectionModelBinderUtil.GetIndexNamesFromValueProviderResult(valueProviderResultIndex);

            return(BindComplexCollectionFromIndexes(actionContext, bindingContext, indexNames));
        }
Пример #8
0
        public void GetIndexNamesFromValueProviderResult_ValueProviderResultIsNull_ReturnsNull()
        {
            // Act
            IEnumerable <string> indexNames = CollectionModelBinderUtil.GetIndexNamesFromValueProviderResult(null);

            // Assert
            Assert.Null(indexNames);
        }
Пример #9
0
        internal static List <TElement> BindComplexCollectionFromIndexes(
            HttpActionContext actionContext,
            ModelBindingContext bindingContext,
            IEnumerable <string> indexNames
            )
        {
            bool indexNamesIsFinite;

            if (indexNames != null)
            {
                indexNamesIsFinite = true;
            }
            else
            {
                indexNamesIsFinite = false;
                indexNames         = CollectionModelBinderUtil.GetZeroBasedIndexes();
            }

            List <TElement> boundCollection = new List <TElement>();

            foreach (string indexName in indexNames)
            {
                string fullChildName = ModelBindingHelper.CreateIndexModelName(
                    bindingContext.ModelName,
                    indexName
                    );
                ModelBindingContext childBindingContext = new ModelBindingContext(bindingContext)
                {
                    ModelMetadata = actionContext
                                    .GetMetadataProvider()
                                    .GetMetadataForType(null, typeof(TElement)),
                    ModelName = fullChildName
                };

                bool   didBind    = false;
                object boundValue = null;
                if (actionContext.Bind(childBindingContext))
                {
                    didBind    = true;
                    boundValue = childBindingContext.Model;

                    // merge validation up
                    bindingContext.ValidationNode.ChildNodes.Add(
                        childBindingContext.ValidationNode
                        );
                }

                // infinite size collection stops on first bind failure
                if (!didBind && !indexNamesIsFinite)
                {
                    break;
                }

                boundCollection.Add(ModelBindingHelper.CastOrDefault <TElement>(boundValue));
            }

            return(boundCollection);
        }
 public override IModelBinder GetBinder(HttpConfiguration configuration, Type modelType)
 {
     return(CollectionModelBinderUtil.GetGenericBinder(
                typeof(IDictionary <,>),
                typeof(Dictionary <,>),
                typeof(DictionaryModelBinder <,>),
                modelType
                ));
 }
Пример #11
0
        // Used when the ValueProvider contains the collection to be bound as multiple elements, e.g. foo[0], foo[1].
        private async Task <List <TElement> > BindComplexCollection(ModelBindingContext bindingContext)
        {
            var indexPropertyName        = ModelBindingHelper.CreatePropertyModelName(bindingContext.ModelName, "index");
            var valueProviderResultIndex = await bindingContext.ValueProvider.GetValueAsync(indexPropertyName);

            var indexNames = CollectionModelBinderUtil.GetIndexNamesFromValueProviderResult(valueProviderResultIndex);

            return(await BindComplexCollectionFromIndexes(bindingContext, indexNames));
        }
Пример #12
0
 public override IModelBinder GetBinder(HttpConfiguration configuration, Type modelType)
 {
     return(CollectionModelBinderUtil.GetGenericBinder(
                typeof(ICollection <>),
                typeof(List <>),
                typeof(CollectionModelBinder <>),
                modelType
                ));
 }
Пример #13
0
        public void GetTypeArgumentsForUpdatableGenericCollection_ModelTypeOpenGeneric_Fail()
        {
            // Arrange
            ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(IList <>));

            // Act
            Type[] typeArguments = CollectionModelBinderUtil.GetTypeArgumentsForUpdatableGenericCollection(null, null, modelMetadata);

            // Assert
            Assert.Null(typeArguments);
        }
Пример #14
0
        public void GetTypeArgumentsForUpdatableGenericCollection_ModelTypeWrongNumberOfGenericArguments_Fail()
        {
            // Arrange
            ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(KeyValuePair <int, string>));

            // Act
            Type[] typeArguments = CollectionModelBinderUtil.GetTypeArgumentsForUpdatableGenericCollection(typeof(ICollection <>), null, modelMetadata);

            // Assert
            Assert.Null(typeArguments);
        }
Пример #15
0
        public void GetIndexNamesFromValueProviderResult_ValueProviderResultReturnsEmptyArray_ReturnsNull()
        {
            // Arrange
            ValueProviderResult vpResult = new ValueProviderResult(new string[0], "", null);

            // Act
            IEnumerable <string> indexNames = CollectionModelBinderUtil.GetIndexNamesFromValueProviderResult(vpResult);

            // Assert
            Assert.Null(indexNames);
        }
Пример #16
0
        public void GetTypeArgumentsForUpdatableGenericCollection_ModelTypeNotGeneric_Fail()
        {
            // Arrange
            ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(int));

            // Act
            Type[] typeArguments = CollectionModelBinderUtil.GetTypeArgumentsForUpdatableGenericCollection(null, null, modelMetadata);

            // Assert
            Assert.IsNull(typeArguments, "The given model type was not generic.");
        }
Пример #17
0
        public void GetIndexNamesFromValueProviderResult_ValueProviderResultReturnsNonEmptyArray_ReturnsArray()
        {
            // Arrange
            ValueProviderResult vpResult = new ValueProviderResult(new[] { "foo", "bar", "baz" }, "foo,bar,baz", null);

            // Act
            IEnumerable <string> indexNames = CollectionModelBinderUtil.GetIndexNamesFromValueProviderResult(vpResult);

            // Assert
            Assert.NotNull(indexNames);
            Assert.Equal(new[] { "foo", "bar", "baz" }, indexNames.ToArray());
        }
Пример #18
0
        public override IModelBinder GetBinder(HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            ModelBindingHelper.ValidateBindingContext(bindingContext);

            if (bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName))
            {
                return(CollectionModelBinderUtil.GetGenericBinder(typeof(ICollection <>), typeof(List <>), typeof(CollectionModelBinder <>), bindingContext.ModelMetadata));
            }
            else
            {
                return(null);
            }
        }
Пример #19
0
        public void GetTypeArgumentsForUpdatableGenericCollection_ReadWriteReference_NewInstanceAssignableToModelType_Success()
        {
            // Arrange
            ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(IList <int>));

            modelMetadata.IsReadOnly = false;

            // Act
            Type[] typeArguments = CollectionModelBinderUtil.GetTypeArgumentsForUpdatableGenericCollection(typeof(ICollection <>), typeof(List <>), modelMetadata);

            // Assert
            CollectionAssert.AreEqual(new Type[] { typeof(int) }, typeArguments, "Mutable reference can be overwritten.");
        }
Пример #20
0
        public void GetTypeArgumentsForUpdatableGenericCollection_ReadWriteReference_NewInstanceNotAssignableToModelType_MutableInstance_Success()
        {
            // Arrange
            ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => new Collection <int>(), typeof(Collection <int>));

            modelMetadata.IsReadOnly = false;

            // Act
            Type[] typeArguments = CollectionModelBinderUtil.GetTypeArgumentsForUpdatableGenericCollection(typeof(ICollection <>), typeof(List <>), modelMetadata);

            // Assert
            Assert.Equal(new[] { typeof(int) }, typeArguments);
        }
Пример #21
0
        public void GetTypeArgumentsForUpdatableGenericCollection_ReadOnlyReference_ModelIsNull_Fail()
        {
            // Arrange
            ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(IList <int>));

            modelMetadata.IsReadOnly = true;

            // Act
            Type[] typeArguments = CollectionModelBinderUtil.GetTypeArgumentsForUpdatableGenericCollection(typeof(ICollection <>), typeof(List <>), modelMetadata);

            // Assert
            Assert.Null(typeArguments);
        }
Пример #22
0
 // Extensibility point that allows the bound collection to be manipulated or transformed before
 // being returned from the binder.
 protected virtual bool CreateOrReplaceCollection(
     HttpActionContext actionContext,
     ModelBindingContext bindingContext,
     IList <TElement> newCollection
     )
 {
     CollectionModelBinderUtil.CreateOrReplaceCollection(
         bindingContext,
         newCollection,
         () => new List <TElement>()
         );
     return(true);
 }
Пример #23
0
        public void GetTypeArgumentsForUpdatableGenericCollection_ReadOnlyReference_ModelInstanceMutable_Valid()
        {
            // Arrange
            ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => new List <int>(), typeof(IList <int>));

            modelMetadata.IsReadOnly = true;

            // Act
            Type[] typeArguments = CollectionModelBinderUtil.GetTypeArgumentsForUpdatableGenericCollection(typeof(IList <>), typeof(List <>), modelMetadata);

            // Assert
            Assert.Equal(new[] { typeof(int) }, typeArguments);
        }
Пример #24
0
        public void GetTypeArgumentsForUpdatableGenericCollection_ReadOnlyReference_ModelInstanceImmutable_Valid()
        {
            // Arrange
            ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => new int[0], typeof(IList <int>));

            modelMetadata.IsReadOnly = true;

            // Act
            Type[] typeArguments = CollectionModelBinderUtil.GetTypeArgumentsForUpdatableGenericCollection(typeof(IList <>), typeof(List <>), modelMetadata);

            // Assert
            Assert.IsNull(typeArguments, "Collection instance is immutable and reference is readonly.");
        }
Пример #25
0
 protected override bool CreateOrReplaceCollection(
     HttpActionContext actionContext,
     ModelBindingContext bindingContext,
     IList <KeyValuePair <TKey, TValue> > newCollection
     )
 {
     CollectionModelBinderUtil.CreateOrReplaceDictionary(
         bindingContext,
         newCollection,
         () => new Dictionary <TKey, TValue>()
         );
     return(true);
 }
Пример #26
0
        private static Type GetCollectionElementType(Type collectionType)
        {
            Contract.Assert(!typeof(IDictionary).IsAssignableFrom(collectionType));

            Type elementType = collectionType.GetElementType();

            if (elementType == null)
            {
                elementType = CollectionModelBinderUtil
                              .GetGenericBinderTypeArgs(typeof(ICollection <>), collectionType)
                              .First();
            }
            return(elementType);
        }
Пример #27
0
        public void GetTypeArgumentsForUpdatableGenericCollection_ReadOnlyReference_ModelInstanceOfWrongType_Fail()
        {
            // Arrange
            ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => new HashSet <int>(), typeof(ICollection <int>));

            modelMetadata.IsReadOnly = true;

            // Act
            Type[] typeArguments = CollectionModelBinderUtil.GetTypeArgumentsForUpdatableGenericCollection(typeof(IList <>), typeof(List <>), modelMetadata);

            // Assert
            // HashSet<> is not an IList<>, so we can't update
            Assert.Null(typeArguments);
        }
Пример #28
0
        public void CreateOrReplaceCollection_OriginalModelNotCollection_CreatesNewInstance()
        {
            // Arrange
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext
            {
                ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(ICollection <int>))
            };

            // Act
            CollectionModelBinderUtil.CreateOrReplaceCollection(bindingContext, new[] { 10, 20, 30 }, () => new List <int>());

            // Assert
            int[] newModel = (bindingContext.Model as ICollection <int>).ToArray();
            Assert.Equal(new[] { 10, 20, 30 }, newModel);
        }
Пример #29
0
        public void CreateOrReplaceCollection_OriginalModelMutable_UpdatesOriginalInstance()
        {
            // Arrange
            List <int> originalInstance = new List <int>()
            {
                10, 20, 30
            };
            ExtensibleModelBindingContext bindingContext = new ExtensibleModelBindingContext()
            {
                ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => originalInstance, typeof(ICollection <int>))
            };

            // Act
            CollectionModelBinderUtil.CreateOrReplaceCollection <int>(bindingContext, new int[] { 40, 50, 60 }, () => new List <int>());

            // Assert
            Assert.AreSame(originalInstance, bindingContext.Model, "Original collection should have been updated.");
            CollectionAssert.AreEqual(new int[] { 40, 50, 60 }, originalInstance);
        }