public async Task DictionaryModelBinder_CreatesEmptyCollection_IfIsTopLevelObject()
        {
            // Arrange
            var binder = new DictionaryModelBinder <string, string>(
                new SimpleTypeModelBinder(typeof(string)),
                new SimpleTypeModelBinder(typeof(string)));

            var bindingContext = CreateContext();

            bindingContext.IsTopLevelObject = true;

            // Lack of prefix and non-empty model name both ignored.
            bindingContext.ModelName = "modelName";

            var metadataProvider = new TestModelMetadataProvider();

            bindingContext.ModelMetadata = metadataProvider.GetMetadataForType(typeof(Dictionary <string, string>));

            bindingContext.ValueProvider = new TestValueProvider(new Dictionary <string, object>());

            // Act
            await binder.BindModelAsync(bindingContext);

            // Assert
            Assert.Empty(Assert.IsType <Dictionary <string, string> >(bindingContext.Result.Model));
            Assert.True(bindingContext.Result.IsModelSet);
        }
        public async Task DictionaryModelBinder_DoesNotCreateCollection_IfNotIsTopLevelObject(string prefix)
        {
            // Arrange
            var binder = new DictionaryModelBinder <int, int>(
                new SimpleTypeModelBinder(typeof(int)),
                new SimpleTypeModelBinder(typeof(int)));

            var bindingContext = CreateContext();

            bindingContext.ModelName = ModelNames.CreatePropertyModelName(prefix, "ListProperty");

            var metadataProvider = new TestModelMetadataProvider();

            bindingContext.ModelMetadata = metadataProvider.GetMetadataForProperty(
                typeof(ModelWithDictionaryProperties),
                nameof(ModelWithDictionaryProperties.DictionaryProperty));

            bindingContext.ValueProvider = new TestValueProvider(new Dictionary <string, object>());

            // Act
            await binder.BindModelAsync(bindingContext);

            // Assert
            Assert.False(bindingContext.Result.IsModelSet);
        }
Example #3
0
        public async Task DictionaryModelBinder_CreatesEmptyCollection_IfIsTopLevelObject()
        {
            // Arrange
            var binder = new DictionaryModelBinder <string, string>(new SimpleTypeModelBinder(), new SimpleTypeModelBinder());

            var context = CreateContext();

            context.IsTopLevelObject = true;

            // Lack of prefix and non-empty model name both ignored.
            context.ModelName = "modelName";

            var metadataProvider = context.OperationBindingContext.MetadataProvider;

            context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(Dictionary <string, string>));

            context.ValueProvider = new TestValueProvider(new Dictionary <string, object>());

            // Act
            var result = await binder.BindModelResultAsync(context);

            // Assert
            Assert.NotEqual(default(ModelBindingResult), result);

            Assert.Empty(Assert.IsType <Dictionary <string, string> >(result.Model));
            Assert.Equal("modelName", result.Key);
            Assert.True(result.IsModelSet);
        }
        public async Task BindModel_FallsBackToBindingValues_WithCustomDictionary(
            string modelName,
            string keyFormat,
            IDictionary <string, string> dictionary)
        {
            // Arrange
            var expectedDictionary = new SortedDictionary <string, string>(dictionary);
            var binder             = new DictionaryModelBinder <string, string>(
                new SimpleTypeModelBinder(typeof(string)),
                new SimpleTypeModelBinder(typeof(string)));

            var bindingContext = CreateContext();

            bindingContext.ModelName = modelName;

            bindingContext.ValueProvider = CreateEnumerableValueProvider(keyFormat, dictionary);
            bindingContext.FieldName     = bindingContext.ModelName;

            var metadataProvider = new TestModelMetadataProvider();

            bindingContext.ModelMetadata = metadataProvider.GetMetadataForProperty(
                typeof(ModelWithDictionaryProperties),
                nameof(ModelWithDictionaryProperties.CustomDictionaryProperty));

            // Act
            await binder.BindModelAsync(bindingContext);

            // Assert
            Assert.True(bindingContext.Result.IsModelSet);

            var resultDictionary = Assert.IsAssignableFrom <SortedDictionary <string, string> >(bindingContext.Result.Model);

            Assert.Equal(expectedDictionary, resultDictionary);
        }
        public async Task BindModel_FallsBackToBindingValues_WithValueTypes(IDictionary <long, int> dictionary)
        {
            // Arrange
            var stringDictionary = dictionary.ToDictionary(kvp => kvp.Key.ToString(), kvp => kvp.Value.ToString());

            var binder = new DictionaryModelBinder <long, int>(
                new SimpleTypeModelBinder(typeof(long)),
                new SimpleTypeModelBinder(typeof(int)));

            var bindingContext = CreateContext();

            bindingContext.ModelName     = "prefix";
            bindingContext.ValueProvider = CreateEnumerableValueProvider("prefix[{0}]", stringDictionary);
            bindingContext.FieldName     = bindingContext.ModelName;

            var metadataProvider = new TestModelMetadataProvider();

            bindingContext.ModelMetadata = metadataProvider.GetMetadataForProperty(
                typeof(ModelWithDictionaryProperties),
                nameof(ModelWithDictionaryProperties.DictionaryWithValueTypesProperty));

            // Act
            await binder.BindModelAsync(bindingContext);

            // Assert
            Assert.True(bindingContext.Result.IsModelSet);

            var resultDictionary = Assert.IsAssignableFrom <IDictionary <long, int> >(bindingContext.Result.Model);

            Assert.Equal(dictionary, resultDictionary);
        }
Example #6
0
        public async Task BindModel_Succeeds(bool isReadOnly)
        {
            // Arrange
            var values = new Dictionary <string, string>()
            {
                { "someName[0].Key", "42" },
                { "someName[0].Value", "forty-two" },
                { "someName[1].Key", "84" },
                { "someName[1].Value", "eighty-four" },
            };

            // Value Provider

            var bindingContext = GetModelBindingContext(isReadOnly, values);

            bindingContext.ValueProvider = CreateEnumerableValueProvider("{0}", values);

            var binder = new DictionaryModelBinder <int, string>(new SimpleTypeModelBinder(), new SimpleTypeModelBinder());

            // Act
            var result = await binder.BindModelResultAsync(bindingContext);

            // Assert
            Assert.True(result.IsModelSet);

            var dictionary = Assert.IsAssignableFrom <IDictionary <int, string> >(result.Model);

            Assert.NotNull(dictionary);
            Assert.Equal(2, dictionary.Count);
            Assert.Equal("forty-two", dictionary[42]);
            Assert.Equal("eighty-four", dictionary[84]);

            // This uses the default IValidationStrategy
            Assert.DoesNotContain(result.Model, bindingContext.ValidationState.Keys);
        }
Example #7
0
        public async Task BindModel_FallsBackToBindingValues(
            string modelName,
            string keyFormat,
            IDictionary <string, string> dictionary)
        {
            // Arrange
            var binder = new DictionaryModelBinder <string, string>(new SimpleTypeModelBinder(), new SimpleTypeModelBinder());

            var context = CreateContext();

            context.ModelName = modelName;
            context.OperationBindingContext.ValueProvider = CreateEnumerableValueProvider(keyFormat, dictionary);
            context.ValueProvider = context.OperationBindingContext.ValueProvider;
            context.FieldName     = modelName;

            var metadataProvider = context.OperationBindingContext.MetadataProvider;

            context.ModelMetadata = metadataProvider.GetMetadataForProperty(
                typeof(ModelWithDictionaryProperties),
                nameof(ModelWithDictionaryProperties.DictionaryProperty));

            // Act
            var result = await binder.BindModelResultAsync(context);

            // Assert
            Assert.True(result.IsModelSet);
            Assert.Equal(modelName, result.Key);

            var resultDictionary = Assert.IsAssignableFrom <IDictionary <string, string> >(result.Model);

            Assert.Equal(dictionary, resultDictionary);
        }
Example #8
0
        public void CanCreateInstance_ReturnsExpectedValue(Type modelType, bool expectedResult)
        {
            // Arrange
            var binder = new DictionaryModelBinder <int, int>(new SimpleTypeModelBinder(), new SimpleTypeModelBinder());

            // Act
            var result = binder.CanCreateInstance(modelType);

            // Assert
            Assert.Equal(expectedResult, result);
        }
Example #9
0
        public async Task DictionaryModelBinder_CreatesEmptyCollectionAndAddsError_IfIsTopLevelObject()
        {
            // Arrange
            var binder = new DictionaryModelBinder <string, string>(
                new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
                new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
                NullLoggerFactory.Instance,
                allowValidatingTopLevelNodes: true);

            var bindingContext = CreateContext();

            bindingContext.IsTopLevelObject = true;
            bindingContext.FieldName        = "fieldName";
            bindingContext.ModelName        = "modelName";

            var metadataProvider = new TestModelMetadataProvider();
            var parameter        = typeof(DictionaryModelBinderTest)
                                   .GetMethod(nameof(ActionWithDictionaryParameter), BindingFlags.Instance | BindingFlags.NonPublic)
                                   .GetParameters()[0];

            metadataProvider
            .ForParameter(parameter)
            .BindingDetails(b => b.IsBindingRequired = true);
            bindingContext.ModelMetadata             = metadataProvider.GetMetadataForParameter(parameter);

            bindingContext.ValueProvider = new TestValueProvider(new Dictionary <string, object>());

            // Act
            await binder.BindModelAsync(bindingContext);

            // Assert
            Assert.Empty(Assert.IsType <Dictionary <string, string> >(bindingContext.Result.Model));
            Assert.True(bindingContext.Result.IsModelSet);

            var keyValuePair = Assert.Single(bindingContext.ModelState);

            Assert.Equal("modelName", keyValuePair.Key);
            var error = Assert.Single(keyValuePair.Value.Errors);

            Assert.Equal("A value for the 'fieldName' parameter or property was not provided.", error.ErrorMessage);
        }
Example #10
0
        public async Task BindModel_WithExistingModel_Succeeds(bool isReadOnly)
        {
            // Arrange
            var values = new Dictionary <string, string>()
            {
                { "someName[0].Key", "42" },
                { "someName[0].Value", "forty-two" },
                { "someName[1].Key", "84" },
                { "someName[1].Value", "eighty-four" },
            };

            var bindingContext = GetModelBindingContext(isReadOnly, values);

            bindingContext.ValueProvider = CreateEnumerableValueProvider("{0}", values);

            var dictionary = new Dictionary <int, string>();

            bindingContext.Model = dictionary;

            var binder = new DictionaryModelBinder <int, string>(
                new SimpleTypeModelBinder(typeof(int), NullLoggerFactory.Instance),
                new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
                NullLoggerFactory.Instance);

            // Act
            await binder.BindModelAsync(bindingContext);

            // Assert
            Assert.True(bindingContext.Result.IsModelSet);

            Assert.Same(dictionary, bindingContext.Result.Model);
            Assert.NotNull(dictionary);
            Assert.Equal(2, dictionary.Count);
            Assert.Equal("forty-two", dictionary[42]);
            Assert.Equal("eighty-four", dictionary[84]);

            // This uses the default IValidationStrategy
            Assert.DoesNotContain(bindingContext.Result.Model, bindingContext.ValidationState.Keys);
        }
        public async Task DictionaryModelBinder_CreatesEmptyCollection_IfIsTopLevelObject(
            bool allowValidatingTopLevelNodes,
            bool isBindingRequired)
        {
            // Arrange
            var expectedErrorCount = isBindingRequired ? 1 : 0;
            var binder             = new DictionaryModelBinder <string, string>(
                new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
                new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
                NullLoggerFactory.Instance,
                allowValidatingTopLevelNodes);

            var bindingContext = CreateContext();

            bindingContext.IsTopLevelObject = true;

            // Lack of prefix and non-empty model name both ignored.
            bindingContext.ModelName = "modelName";

            var metadataProvider = new TestModelMetadataProvider();
            var parameter        = typeof(DictionaryModelBinderTest)
                                   .GetMethod(nameof(ActionWithDictionaryParameter), BindingFlags.Instance | BindingFlags.NonPublic)
                                   .GetParameters()[0];

            metadataProvider
            .ForParameter(parameter)
            .BindingDetails(b => b.IsBindingRequired = isBindingRequired);
            bindingContext.ModelMetadata             = metadataProvider.GetMetadataForParameter(parameter);

            bindingContext.ValueProvider = new TestValueProvider(new Dictionary <string, object>());

            // Act
            await binder.BindModelAsync(bindingContext);

            // Assert
            Assert.Empty(Assert.IsType <Dictionary <string, string> >(bindingContext.Result.Model));
            Assert.True(bindingContext.Result.IsModelSet);
            Assert.Equal(expectedErrorCount, bindingContext.ModelState.ErrorCount);
        }
Example #12
0
        public async Task BindModel_DoesNotFallBack_WithoutEnumerableValueProvider()
        {
            // Arrange
            var dictionary = new Dictionary <string, string>(StringComparer.Ordinal)
            {
                { "one", "one" },
                { "two", "two" },
                { "three", "three" },
            };

            var binder = new DictionaryModelBinder <string, string>(
                new SimpleTypeModelBinder(typeof(string)),
                new SimpleTypeModelBinder(typeof(string)));

            var context = CreateContext();

            context.ModelName     = "prefix";
            context.ValueProvider = CreateTestValueProvider("prefix[{0}]", dictionary);
            context.FieldName     = context.ModelName;

            var metadataProvider = new TestModelMetadataProvider();

            context.ModelMetadata = metadataProvider.GetMetadataForProperty(
                typeof(ModelWithDictionaryProperties),
                nameof(ModelWithDictionaryProperties.DictionaryProperty));

            // Act
            var result = await binder.BindModelResultAsync(context);

            // Assert
            Assert.NotEqual(default(ModelBindingResult), result);
            Assert.True(result.IsModelSet);
            Assert.Equal("prefix", result.Key);

            var resultDictionary = Assert.IsAssignableFrom <IDictionary <string, string> >(result.Model);

            Assert.Empty(resultDictionary);
        }
Example #13
0
        public async Task DictionaryModelBinder_DoesNotCreateCollection_IfNotIsTopLevelObject(string prefix)
        {
            // Arrange
            var binder = new DictionaryModelBinder <int, int>(new SimpleTypeModelBinder(), new SimpleTypeModelBinder());

            var context = CreateContext();

            context.ModelName = ModelNames.CreatePropertyModelName(prefix, "ListProperty");

            var metadataProvider = context.OperationBindingContext.MetadataProvider;

            context.ModelMetadata = metadataProvider.GetMetadataForProperty(
                typeof(ModelWithDictionaryProperties),
                nameof(ModelWithDictionaryProperties.DictionaryProperty));

            context.ValueProvider = new TestValueProvider(new Dictionary <string, object>());

            // Act
            var result = await binder.BindModelResultAsync(context);

            // Assert
            Assert.Equal(default(ModelBindingResult), result);
        }
Example #14
0
        public async Task DictionaryModelBinder_DoesNotCreateCollection_IfNotIsTopLevelObject(
            string prefix,
            bool allowValidatingTopLevelNodes,
            bool isBindingRequired)
        {
            // Arrange
            var binder = new DictionaryModelBinder <int, int>(
                new SimpleTypeModelBinder(typeof(int), NullLoggerFactory.Instance),
                new SimpleTypeModelBinder(typeof(int), NullLoggerFactory.Instance),
                NullLoggerFactory.Instance,
                allowValidatingTopLevelNodes);

            var bindingContext = CreateContext();

            bindingContext.ModelName = ModelNames.CreatePropertyModelName(prefix, "ListProperty");

            var metadataProvider = new TestModelMetadataProvider();

            metadataProvider
            .ForProperty(
                typeof(ModelWithDictionaryProperties),
                nameof(ModelWithDictionaryProperties.DictionaryProperty))
            .BindingDetails(b => b.IsBindingRequired = isBindingRequired);
            bindingContext.ModelMetadata             = metadataProvider.GetMetadataForProperty(
                typeof(ModelWithDictionaryProperties),
                nameof(ModelWithDictionaryProperties.DictionaryProperty));

            bindingContext.ValueProvider = new TestValueProvider(new Dictionary <string, object>());

            // Act
            await binder.BindModelAsync(bindingContext);

            // Assert
            Assert.False(bindingContext.Result.IsModelSet);
            Assert.Equal(0, bindingContext.ModelState.ErrorCount);
        }
        public async Task BindModel_FallsBackToBindingValues_WithComplexValues()
        {
            // Arrange
            var dictionary = new Dictionary <int, ModelWithProperties>
            {
                { 23, new ModelWithProperties {
                      Id = 43, Name = "Wilma"
                  } },
                { 27, new ModelWithProperties {
                      Id = 98, Name = "Fred"
                  } },
            };
            var stringDictionary = new Dictionary <string, string>
            {
                { "prefix[23].Id", "43" },
                { "prefix[23].Name", "Wilma" },
                { "prefix[27].Id", "98" },
                { "prefix[27].Name", "Fred" },
            };

            var bindingContext = CreateContext();

            bindingContext.ModelName     = "prefix";
            bindingContext.ValueProvider = CreateEnumerableValueProvider("{0}", stringDictionary);
            bindingContext.FieldName     = bindingContext.ModelName;

            var metadataProvider = new TestModelMetadataProvider();

            bindingContext.ModelMetadata = metadataProvider.GetMetadataForProperty(
                typeof(ModelWithDictionaryProperties),
                nameof(ModelWithDictionaryProperties.DictionaryWithComplexValuesProperty));

            var valueMetadata = metadataProvider.GetMetadataForType(typeof(ModelWithProperties));

            var binder = new DictionaryModelBinder <int, ModelWithProperties>(
                new SimpleTypeModelBinder(typeof(int)),
                new ComplexTypeModelBinder(new Dictionary <ModelMetadata, IModelBinder>()
            {
                { valueMetadata.Properties["Id"], new SimpleTypeModelBinder(typeof(int)) },
                { valueMetadata.Properties["Name"], new SimpleTypeModelBinder(typeof(string)) },
            }));

            // Act
            await binder.BindModelAsync(bindingContext);

            // Assert
            Assert.True(bindingContext.Result.IsModelSet);

            var resultDictionary = Assert.IsAssignableFrom <IDictionary <int, ModelWithProperties> >(bindingContext.Result.Model);

            Assert.Equal(dictionary, resultDictionary);

            // This requires a non-default IValidationStrategy
            Assert.Contains(bindingContext.Result.Model, bindingContext.ValidationState.Keys);
            var entry    = bindingContext.ValidationState[bindingContext.Result.Model];
            var strategy = Assert.IsType <ShortFormDictionaryValidationStrategy <int, ModelWithProperties> >(entry.Strategy);

            Assert.Equal(
                new KeyValuePair <string, int>[]
            {
                new KeyValuePair <string, int>("23", 23),
                new KeyValuePair <string, int>("27", 27),
            }.OrderBy(kvp => kvp.Key),
                strategy.KeyMappings.OrderBy(kvp => kvp.Key));
        }