public async Task BindModelAsync_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,
                CreateMockValidator());

            var controllerContext = new ControllerContext();

            // Act & Assert
            await parameterBinder.BindModelAsync(controllerContext, new SimpleValueProvider(), parameterDescriptor);

            Assert.True(binderExecuted);
        }
Пример #2
0
        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);
            });
        }
Пример #3
0
        public void EnterNestedScope_CopiesProperties()
        {
            // Arrange
            var bindingContext = new DefaultModelBindingContext
            {
                Model                   = new object(),
                ModelMetadata           = new TestModelMetadataProvider().GetMetadataForType(typeof(object)),
                ModelName               = "theName",
                OperationBindingContext = new OperationBindingContext(),
                ValueProvider           = new SimpleValueProvider(),
                ModelState              = new ModelStateDictionary(),
            };

            var metadataProvider = new TestModelMetadataProvider();

            metadataProvider.ForType <object>().BindingDetails(d =>
            {
                d.BindingSource   = BindingSource.Custom;
                d.BinderType      = typeof(TestModelBinder);
                d.BinderModelName = "custom";
            });

            var newModelMetadata = metadataProvider.GetMetadataForType(typeof(object));

            // Act
            var originalBinderModelName         = bindingContext.BinderModelName;
            var originalBinderType              = bindingContext.BinderType;
            var originalBindingSource           = bindingContext.BindingSource;
            var originalModelState              = bindingContext.ModelState;
            var originalOperationBindingContext = bindingContext.OperationBindingContext;
            var originalValueProvider           = bindingContext.ValueProvider;

            var disposable = bindingContext.EnterNestedScope(
                modelMetadata: newModelMetadata,
                fieldName: "fieldName",
                modelName: "modelprefix.fieldName",
                model: null);

            // Assert
            Assert.Same(newModelMetadata.BinderModelName, bindingContext.BinderModelName);
            Assert.Same(newModelMetadata.BinderType, bindingContext.BinderType);
            Assert.Same(newModelMetadata.BindingSource, bindingContext.BindingSource);
            Assert.False(bindingContext.FallbackToEmptyPrefix);
            Assert.Equal("fieldName", bindingContext.FieldName);
            Assert.False(bindingContext.IsTopLevelObject);
            Assert.Null(bindingContext.Model);
            Assert.Same(newModelMetadata, bindingContext.ModelMetadata);
            Assert.Equal("modelprefix.fieldName", bindingContext.ModelName);
            Assert.Same(originalModelState, bindingContext.ModelState);
            Assert.Same(originalOperationBindingContext, bindingContext.OperationBindingContext);
            Assert.Same(originalValueProvider, bindingContext.ValueProvider);

            disposable.Dispose();
        }
Пример #4
0
        public void CreateBinder_PassesExpectedBindingInfo(
            BindingInfo parameterBindingInfo,
            BindingMetadata bindingMetadata,
            BindingInfo expectedInfo)
        {
            // Arrange
            var metadataProvider = new TestModelMetadataProvider();

            metadataProvider.ForType <Employee>().BindingDetails(binding =>
            {
                binding.BinderModelName = bindingMetadata.BinderModelName;
                binding.BinderType      = bindingMetadata.BinderType;
                binding.BindingSource   = bindingMetadata.BindingSource;
                if (bindingMetadata.PropertyFilterProvider != null)
                {
                    binding.PropertyFilterProvider = bindingMetadata.PropertyFilterProvider;
                }
            });

            var modelBinder         = Mock.Of <IModelBinder>();
            var modelBinderProvider = new TestModelBinderProvider(context =>
            {
                Assert.Equal(typeof(Employee), context.Metadata.ModelType);

                Assert.NotNull(context.BindingInfo);
                Assert.Equal(expectedInfo.BinderModelName, context.BindingInfo.BinderModelName, StringComparer.Ordinal);
                Assert.Equal(expectedInfo.BinderType, context.BindingInfo.BinderType);
                Assert.Equal(expectedInfo.BindingSource, context.BindingInfo.BindingSource);
                Assert.Same(expectedInfo.PropertyFilterProvider, context.BindingInfo.PropertyFilterProvider);

                return(modelBinder);
            });

            var options = Options.Create(new MvcOptions());

            options.Value.ModelBinderProviders.Insert(0, modelBinderProvider);

            var factory = new ModelBinderFactory(
                metadataProvider,
                options,
                GetServices());
            var factoryContext = new ModelBinderFactoryContext
            {
                BindingInfo = parameterBindingInfo,
                Metadata    = metadataProvider.GetMetadataForType(typeof(Employee)),
            };

            // Act & Assert
            var result = factory.CreateBinder(factoryContext);

            // Confirm our IModelBinderProvider was called.
            Assert.Same(modelBinder, result);
        }
        public async Task BindModel_IsGreedy()
        {
            // Arrange
            var provider = new TestModelMetadataProvider();

            provider.ForType <Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);

            var bindingContext = GetBindingContext(typeof(Person), metadataProvider: provider);

            var binder = bindingContext.OperationBindingContext.ModelBinder;

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

            // Assert
            Assert.NotNull(binderResult);
            Assert.False(binderResult.IsModelSet);
        }
        public async Task BindModel_IsGreedy_IgnoresMetadataWithNoSource()
        {
            // Arrange
            var provider = new TestModelMetadataProvider();

            provider.ForType <Person>().BindingDetails(d => d.BindingSource = null);

            var bindingContext = GetBindingContext(typeof(Person), metadataProvider: provider);

            bindingContext.BindingSource = null;

            var binder = bindingContext.OperationBindingContext.ModelBinder;

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

            // Assert
            Assert.Equal(default(ModelBindingResult), binderResult);
        }
Пример #7
0
        public void GetBindingInfo_WithAttributesAndModelMetadata_UsesModelBinderFromModelMetadata_WhenNotFoundViaAttributes()
        {
            // Arrange
            var attributes = new object[] { new ControllerAttribute(), new BindNeverAttribute(), };
            var modelType  = typeof(Guid);
            var provider   = new TestModelMetadataProvider();

            provider.ForType(modelType).BindingDetails(metadata =>
            {
                metadata.BinderType = typeof(ComplexTypeModelBinder);
            });
            var modelMetadata = provider.GetMetadataForType(modelType);

            // Act
            var bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);

            // Assert
            Assert.NotNull(bindingInfo);
            Assert.Same(typeof(ComplexTypeModelBinder), bindingInfo.BinderType);
        }
Пример #8
0
        public void GetBindingInfo_WithAttributesAndModelMetadata_UsesPropertyPredicateProviderFromModelMetadata_WhenNotFoundViaAttributes()
        {
            // Arrange
            var attributes             = new object[] { new ModelBinderAttribute(typeof(object)), new ControllerAttribute(), new BindNeverAttribute(), };
            var propertyFilterProvider = Mock.Of <IPropertyFilterProvider>();
            var modelType = typeof(Guid);
            var provider  = new TestModelMetadataProvider();

            provider.ForType(modelType).BindingDetails(metadata =>
            {
                metadata.PropertyFilterProvider = propertyFilterProvider;
            });
            var modelMetadata = provider.GetMetadataForType(modelType);

            // Act
            var bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);

            // Assert
            Assert.NotNull(bindingInfo);
            Assert.Same(propertyFilterProvider, bindingInfo.PropertyFilterProvider);
        }
        public async Task CustomFormatterDeserializationException_AddedToModelState()
        {
            // Arrange
            var httpContext = new DefaultHttpContext();

            httpContext.Request.Body        = new MemoryStream(Encoding.UTF8.GetBytes("Bad data!"));
            httpContext.Request.ContentType = "text/xyz";

            var provider = new TestModelMetadataProvider();

            provider.ForType <Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);

            var bindingContext = GetBindingContext(
                typeof(Person),
                inputFormatters: new[] { new XyzFormatter() },
                httpContext: httpContext,
                metadataProvider: provider);

            var binder = bindingContext.OperationBindingContext.ModelBinder;

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

            // Assert

            // Returns non-null because it understands the metadata type.
            Assert.NotNull(binderResult);
            Assert.False(binderResult.IsModelSet);
            Assert.Null(binderResult.Model);

            // Key is the empty string because this was a top-level binding.
            var entry = Assert.Single(bindingContext.ModelState);

            Assert.Equal(string.Empty, entry.Key);
            var errorMessage = Assert.Single(entry.Value.Errors).Exception.Message;

            Assert.Equal("Your input is bad!", errorMessage);
        }
Пример #10
0
        public async Task NullFormatterError_AddedToModelState()
        {
            // Arrange
            var httpContext = new DefaultHttpContext();

            httpContext.Request.ContentType = "text/xyz";

            var provider = new TestModelMetadataProvider();

            provider.ForType <Person>().BindingDetails(d => d.BindingSource = BindingSource.Body);

            var bindingContext = GetBindingContext(
                typeof(Person),
                inputFormatters: null,
                httpContext: httpContext,
                metadataProvider: provider);

            var binder = bindingContext.OperationBindingContext.ModelBinder;

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

            // Assert

            // Returns non-null result because it understands the metadata type.
            Assert.NotNull(binderResult);
            Assert.False(binderResult.IsModelSet);
            Assert.Null(binderResult.Model);

            // Key is the empty string because this was a top-level binding.
            var entry = Assert.Single(bindingContext.ModelState);

            Assert.Equal(string.Empty, entry.Key);
            var errorMessage = Assert.Single(entry.Value.Errors).Exception.Message;

            Assert.Equal("Unsupported content type 'text/xyz'.", errorMessage);
        }
Пример #11
0
        private static DefaultModelBindingContext GetBindingContext(Type modelType)
        {
            var metadataProvider = new TestModelMetadataProvider();

            metadataProvider.ForType(modelType).BindingDetails(d => d.BindingSource = BindingSource.Services);
            var modelMetadata = metadataProvider.GetMetadataForType(modelType);


            var services = new ServiceCollection();

            services.AddSingleton <IService>(new Service());

            var bindingContext = new DefaultModelBindingContext
            {
                ModelMetadata           = modelMetadata,
                ModelName               = "modelName",
                FieldName               = "modelName",
                ModelState              = new ModelStateDictionary(),
                OperationBindingContext = new OperationBindingContext
                {
                    ActionContext = new ActionContext()
                    {
                        HttpContext = new DefaultHttpContext()
                        {
                            RequestServices = services.BuildServiceProvider(),
                        }
                    },
                    ModelBinder      = new HeaderModelBinder(),
                    MetadataProvider = metadataProvider,
                },
                BinderModelName = modelMetadata.BinderModelName,
                BindingSource   = modelMetadata.BindingSource,
                ValidationState = new ValidationStateDictionary(),
            };

            return(bindingContext);
        }
Пример #12
0
        public void GetBindingInfo_WithAttributesAndModelMetadata_UsesBinderNameFromModelMetadata_WhenNotFoundViaAttributes()
        {
            // Arrange
            var attributes = new object[] { new ModelBinderAttribute(typeof(object)), new ControllerAttribute(), new BindNeverAttribute(), };
            var modelType  = typeof(Guid);
            var provider   = new TestModelMetadataProvider();

            provider.ForType(modelType).BindingDetails(metadata =>
            {
                metadata.BindingSource   = BindingSource.Special;
                metadata.BinderType      = typeof(string);
                metadata.BinderModelName = "Different";
            });
            var modelMetadata = provider.GetMetadataForType(modelType);

            // Act
            var bindingInfo = BindingInfo.GetBindingInfo(attributes, modelMetadata);

            // Assert
            Assert.NotNull(bindingInfo);
            Assert.Same(typeof(object), bindingInfo.BinderType);
            Assert.Same("Different", bindingInfo.BinderModelName);
            Assert.Same(BindingSource.Custom, bindingInfo.BindingSource);
        }