コード例 #1
0
        public async Task BindModelAsync_ForProperty_UsesValidationFromActualModel_WhenDerivedModelIsSet()
        {
            // Arrange
            var property            = typeof(TestController).GetProperty(nameof(TestController.Model));
            var parameterDescriptor = new ControllerBoundPropertyDescriptor
            {
                PropertyInfo = property,
                Name         = property.Name,
            };

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

            var model = new DerivedModel();
            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}.{nameof(DerivedPerson.DerivedProperty)}", kvp.Key);
                var error = Assert.Single(kvp.Value.Errors);
                Assert.Equal("The DerivedProperty field is required.", error.ErrorMessage);
            });
        }
コード例 #2
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() }),
                _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);
        }
コード例 #3
0
        public async Task BindModelAsync_ForOverlappingParametersWithSuppressions_InValid_WithInValidSecondParameter()
        {
            // 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.");

            // Second ModelState key is empty to match BodyModelBinder.
            modelState.AddModelError(string.Empty, "This is also 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);

            var modelBindingResult = ModelBindingResult.Failed();
            var modelBinder        = CreateMockModelBinder(modelBindingResult);

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

            // Assert
            Assert.False(result.IsModelSet);
            Assert.False(modelState.IsValid);
            Assert.Collection(
                modelState,
                kvp =>
            {
                Assert.Empty(kvp.Key);
                Assert.Equal(ModelValidationState.Invalid, kvp.Value.ValidationState);
                var error = Assert.Single(kvp.Value.Errors);
                Assert.Equal("This is also not valid.", error.ErrorMessage);
            },
                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);
            });
        }
コード例 #4
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);
        }