Exemple #1
0
        public async Task BindModelAsync_PassesExpectedBindingInfoAndMetadata_IfPrefixMatches()
        {
            // Arrange
            var expectedModelName = "expectedName";
            var binderExecuted    = false;

            var metadataProvider = new TestModelMetadataProvider();
            var metadata         = metadataProvider.GetMetadataForType(typeof(Person));
            var modelBinder      = new Mock <IModelBinder>();

            modelBinder
            .Setup(b => b.BindModelAsync(It.IsAny <ModelBindingContext>()))
            .Callback((ModelBindingContext context) =>
            {
                Assert.Equal(expectedModelName, context.ModelName, StringComparer.Ordinal);
            })
            .Returns(Task.CompletedTask);

            var parameterDescriptor = new ParameterDescriptor
            {
                Name          = expectedModelName,
                ParameterType = typeof(Person),
            };

            var factory = new Mock <IModelBinderFactory>(MockBehavior.Strict);

            factory
            .Setup(f => f.CreateBinder(It.IsAny <ModelBinderFactoryContext>()))
            .Callback((ModelBinderFactoryContext context) =>
            {
                binderExecuted = true;
                // Confirm expected data is passed through to ModelBindingFactory.
                Assert.Null(context.BindingInfo);
                Assert.Same(parameterDescriptor, context.CacheToken);
                Assert.Equal(metadata, context.Metadata);
            })
            .Returns(modelBinder.Object);

            var argumentBinder = new ParameterBinder(
                metadataProvider,
                factory.Object,
                Mock.Of <IObjectModelValidator>(),
                NullLoggerFactory.Instance);

            var valueProvider = new SimpleValueProvider
            {
                { expectedModelName, new object() },
            };
            var valueProviderFactory = new SimpleValueProviderFactory(valueProvider);

            var controllerContext = GetControllerContext();

            // Act & Assert
            await argumentBinder.BindModelAsync(controllerContext, valueProvider, parameterDescriptor);

            Assert.True(binderExecuted);
        }
        public async Task BindModelAsync_ForOverlappingParametersWithSuppressions_InValid_WithValidSecondParameter()
        {
            // Arrange
            var parameterDescriptor = new ParameterDescriptor
            {
                Name          = "patchDocument",
                ParameterType = typeof(IJsonPatchDocument),
            };

            var actionContext = GetControllerContext();
            var modelState    = actionContext.ModelState;

            // First ModelState key is not empty to match SimpleTypeModelBinder.
            modelState.SetModelValue("id", "notAGuid", "notAGuid");
            modelState.AddModelError("id", "This is not valid.");

            var modelMetadataProvider = new TestModelMetadataProvider();

            modelMetadataProvider.ForType <IJsonPatchDocument>().ValidationDetails(v => v.ValidateChildren = false);
            var modelMetadata = modelMetadataProvider.GetMetadataForType(typeof(IJsonPatchDocument));

            var parameterBinder = new ParameterBinder(
                modelMetadataProvider,
                Mock.Of <IModelBinderFactory>(),
                new DefaultObjectValidator(
                    modelMetadataProvider,
                    new[] { TestModelValidatorProvider.CreateDefaultProvider() },
                    new MvcOptions()),
                _optionsAccessor,
                NullLoggerFactory.Instance);

            // BodyModelBinder does not update ModelState in success case.
            var modelBindingResult = ModelBindingResult.Success(new JsonPatchDocument());
            var modelBinder        = CreateMockModelBinder(modelBindingResult);

            // Act
            var result = await parameterBinder.BindModelAsync(
                actionContext,
                modelBinder,
                new SimpleValueProvider(),
                parameterDescriptor,
                modelMetadata,
                value : null);

            // Assert
            Assert.True(result.IsModelSet);
            Assert.False(modelState.IsValid);
            Assert.Collection(
                modelState,
                kvp =>
            {
                Assert.Equal("id", kvp.Key);
                Assert.Equal(ModelValidationState.Invalid, kvp.Value.ValidationState);
                var error = Assert.Single(kvp.Value.Errors);
                Assert.Equal("This is not valid.", error.ErrorMessage);
            });
        }
Exemple #3
0
        public async Task BindModelAsync_ForParameter_UsesValidationFromParameter_WhenDerivedModelIsSet()
        {
            // Arrange
            var method              = GetType().GetMethod(nameof(TestMethodWithAttributes), BindingFlags.NonPublic | BindingFlags.Instance);
            var parameter           = method.GetParameters()[0];
            var parameterDescriptor = new ControllerParameterDescriptor
            {
                ParameterInfo = parameter,
                Name          = parameter.Name,
            };

            var actionContext         = GetControllerContext();
            var modelMetadataProvider = new TestModelMetadataProvider();

            var model = new DerivedPerson {
                DerivedProperty = "SomeValue"
            };
            var modelBindingResult = ModelBindingResult.Success(model);

            var parameterBinder = new ParameterBinder(
                modelMetadataProvider,
                Mock.Of <IModelBinderFactory>(),
                new DefaultObjectValidator(
                    modelMetadataProvider,
                    new[] { TestModelValidatorProvider.CreateDefaultProvider() },
                    new MvcOptions()),
                _optionsAccessor,
                NullLoggerFactory.Instance);

            var modelMetadata = modelMetadataProvider.GetMetadataForParameter(parameter);
            var modelBinder   = CreateMockModelBinder(modelBindingResult);

            // Act
            var result = await parameterBinder.BindModelAsync(
                actionContext,
                modelBinder,
                CreateMockValueProvider(),
                parameterDescriptor,
                modelMetadata,
                value : null);

            // Assert
            Assert.True(result.IsModelSet);
            Assert.Same(model, result.Model);

            Assert.False(actionContext.ModelState.IsValid);
            Assert.Collection(
                actionContext.ModelState,
                kvp =>
            {
                Assert.Equal(parameter.Name, kvp.Key);
                var error = Assert.Single(kvp.Value.Errors);
                Assert.Equal("Always Invalid", error.ErrorMessage);
            });
        }
Exemple #4
0
        public async Task BindModelAsync_ForProperty_UsesValidationOnProperty_WhenDerivedModelIsSet()
        {
            // Arrange
            var property            = typeof(TestControllerWithValidatedProperties).GetProperty(nameof(TestControllerWithValidatedProperties.Model));
            var parameterDescriptor = new ControllerBoundPropertyDescriptor
            {
                PropertyInfo = property,
                Name         = property.Name,
            };

            var actionContext         = GetControllerContext();
            var modelMetadataProvider = new TestModelMetadataProvider();

            var model = new DerivedModel {
                DerivedProperty = "some value"
            };
            var modelBindingResult = ModelBindingResult.Success(model);

            var parameterBinder = new ParameterBinder(
                modelMetadataProvider,
                Mock.Of <IModelBinderFactory>(),
                new DefaultObjectValidator(
                    modelMetadataProvider,
                    new[] { TestModelValidatorProvider.CreateDefaultProvider() },
                    new MvcOptions()),
                _optionsAccessor,
                NullLoggerFactory.Instance);

            var modelMetadata = modelMetadataProvider.GetMetadataForProperty(property.DeclaringType, property.Name);
            var modelBinder   = CreateMockModelBinder(modelBindingResult);

            // Act
            var result = await parameterBinder.BindModelAsync(
                actionContext,
                modelBinder,
                CreateMockValueProvider(),
                parameterDescriptor,
                modelMetadata,
                value : null);

            // Assert
            Assert.True(result.IsModelSet);
            Assert.Same(model, result.Model);

            Assert.False(actionContext.ModelState.IsValid);
            Assert.Collection(
                actionContext.ModelState,
                kvp =>
            {
                Assert.Equal($"{property.Name}", kvp.Key);
                var error = Assert.Single(kvp.Value.Errors);
                Assert.Equal("Always Invalid", error.ErrorMessage);
            });
        }
Exemple #5
0
        public async Task BindModelAsync_ForOverlappingParameters_InValid_WithInValidFirstParameterAndSecondNull()
        {
            // Arrange
            var parameterDescriptor = new ParameterDescriptor
            {
                BindingInfo = new BindingInfo
                {
                    BinderModelName = "id",
                },
                Name          = "identifier",
                ParameterType = typeof(string),
            };

            var actionContext = GetControllerContext();
            var modelState    = actionContext.ModelState;

            // Mimic ModelStateEntry when first parameter is [FromRoute] int id and request URI is /api/values/notAnInt
            modelState.SetModelValue("id", "notAnInt", "notAnInt");
            modelState.AddModelError("id", "This is not valid.");

            var modelMetadataProvider = new TestModelMetadataProvider();
            var modelMetadata         = modelMetadataProvider.GetMetadataForType(typeof(string));
            var parameterBinder       = new ParameterBinder(
                modelMetadataProvider,
                Mock.Of <IModelBinderFactory>(),
                new DefaultObjectValidator(
                    modelMetadataProvider,
                    new[] { TestModelValidatorProvider.CreateDefaultProvider() },
                    new MvcOptions()),
                _optionsAccessor,
                NullLoggerFactory.Instance);

            // Mimic result when second parameter is [FromQuery(Name = "id")] string identifier and query is ?id
            var modelBindingResult = ModelBindingResult.Success(null);
            var modelBinder        = CreateMockModelBinder(modelBindingResult);

            // Act
            var result = await parameterBinder.BindModelAsync(
                actionContext,
                modelBinder,
                new SimpleValueProvider(),
                parameterDescriptor,
                modelMetadata,
                value : null);

            // Assert
            Assert.True(result.IsModelSet);
            Assert.False(modelState.IsValid);
            var keyValuePair = Assert.Single(modelState);

            Assert.Equal("id", keyValuePair.Key);
            Assert.Equal(ModelValidationState.Invalid, keyValuePair.Value.ValidationState);
        }
Exemple #6
0
        public async Task ObsoleteBindModelAsync_PassesExpectedBindingInfoAndMetadata_IfPrefixDoesNotMatch(
            BindingInfo parameterBindingInfo,
            string metadataBinderModelName,
            string parameterName,
            string expectedModelName)
        {
            // Arrange
            var binderExecuted   = false;
            var metadataProvider = new TestModelMetadataProvider();

            metadataProvider.ForType <Person>().BindingDetails(binding =>
            {
                binding.BinderModelName = metadataBinderModelName;
            });

            var metadata    = metadataProvider.GetMetadataForType(typeof(Person));
            var modelBinder = new Mock <IModelBinder>();

            modelBinder
            .Setup(b => b.BindModelAsync(It.IsAny <ModelBindingContext>()))
            .Callback((ModelBindingContext context) =>
            {
                Assert.Equal(expectedModelName, context.ModelName, StringComparer.Ordinal);
            })
            .Returns(Task.CompletedTask);

            var parameterDescriptor = new ParameterDescriptor
            {
                BindingInfo   = parameterBindingInfo,
                Name          = parameterName,
                ParameterType = typeof(Person),
            };

            var factory = new Mock <IModelBinderFactory>(MockBehavior.Strict);

            factory
            .Setup(f => f.CreateBinder(It.IsAny <ModelBinderFactoryContext>()))
            .Callback((ModelBinderFactoryContext context) =>
            {
                binderExecuted = true;
                // Confirm expected data is passed through to ModelBindingFactory.
                Assert.Same(parameterDescriptor.BindingInfo, context.BindingInfo);
                Assert.Same(parameterDescriptor, context.CacheToken);
                Assert.Equal(metadata, context.Metadata);
            })
            .Returns(modelBinder.Object);

            var parameterBinder = new ParameterBinder(
                metadataProvider,
                factory.Object,
                Mock.Of <IObjectModelValidator>(),
                _optionsAccessor,
                NullLoggerFactory.Instance);

            var controllerContext = GetControllerContext();

            // Act & Assert
#pragma warning disable CS0618 // Type or member is obsolete
            await parameterBinder.BindModelAsync(controllerContext, new SimpleValueProvider(), parameterDescriptor);

#pragma warning restore CS0618 // Type or member is obsolete
            Assert.True(binderExecuted);
        }