public void GenerateDisplay_CorrectlyCallsTemplateService()
        {
            // Arrange
            var purpose            = TemplatePurposes.Display;
            var expression         = "Age";
            var templateName       = "templateName";
            var htmlFieldName      = "htmlFieldName";
            var additionalViewData = new { additional = "view data" };
            var expected           = new Mock <IHtmlContent>(MockBehavior.Strict);
            var containerMetadata  = _metadataProvider.GetMetadataForType(typeof(TestModel));
            var propertyMetadata   = _metadataProvider.GetMetadataForProperty(typeof(TestModel), expression);

            _templateService.Setup(m =>
                                   m.RenderTemplate(
                                       _viewContext,
                                       _viewContext.ViewData,
                                       It.Is <ModelExplorer>(exp =>
                                                             exp.Metadata == propertyMetadata &&
                                                             exp.Container.Metadata == containerMetadata),
                                       purpose,
                                       htmlFieldName,
                                       templateName,
                                       additionalViewData))
            .Returns(expected.Object)
            .Verifiable();

            // Act
            var result = _htmlHelper.Display(expression, templateName, htmlFieldName, additionalViewData);

            // Assert
            result.Should().BeSameAs(expected.Object);
            _templateService.Verify();
        }
        private static ModelBindingContext GetBindingContext(Type modelType, Type binderType = null)
        {
            var metadataProvider = new TestModelMetadataProvider();

            metadataProvider.ForType(modelType).BindingDetails(bd => bd.BinderType = binderType);

            var operationBindingContext = new OperationBindingContext
            {
                MetadataProvider  = metadataProvider,
                HttpContext       = new DefaultHttpContext(),
                ValidatorProvider = Mock.Of <IModelValidatorProvider>(),
            };

            var bindingContext = new ModelBindingContext
            {
                ModelMetadata           = metadataProvider.GetMetadataForType(modelType),
                ModelName               = "someName",
                ValueProvider           = Mock.Of <IValueProvider>(),
                ModelState              = new ModelStateDictionary(),
                OperationBindingContext = operationBindingContext,
                BinderType              = binderType
            };

            return(bindingContext);
        }
示例#3
0
        private static ModelBindingContext GetModelBindingContext(
            IValueProvider valueProvider,
            bool isReadOnly = false)
        {
            var metadataProvider = new TestModelMetadataProvider();

            metadataProvider.ForType <IList <int> >().BindingDetails(bd => bd.IsReadOnly = isReadOnly);

            var bindingContext = new ModelBindingContext
            {
                ModelMetadata           = metadataProvider.GetMetadataForType(typeof(IList <int>)),
                ModelName               = "someName",
                ModelState              = new ModelStateDictionary(),
                ValueProvider           = valueProvider,
                OperationBindingContext = new OperationBindingContext
                {
                    ModelBinder      = CreateIntBinder(),
                    MetadataProvider = metadataProvider
                },
                ValidationState = new ValidationStateDictionary(),
                FieldName       = "testfieldname",
            };

            return(bindingContext);
        }
示例#4
0
    public void GetBindingInfo_WithAttributesAndModelMetadata_UsesBinderNameFromModelMetadata_WhenNotFoundViaAttributes()
    {
        // Arrange
        var attributes = new object[]
        {
            new ModelBinderAttribute(typeof(ComplexObjectModelBinder)),
            new ControllerAttribute(),
            new BindNeverAttribute(),
        };
        var modelType = typeof(Guid);
        var provider  = new TestModelMetadataProvider();

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

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

        // Assert
        Assert.NotNull(bindingInfo);
        Assert.Same(typeof(ComplexObjectModelBinder), bindingInfo.BinderType);
        Assert.Same("Different", bindingInfo.BinderModelName);
        Assert.Same(BindingSource.Custom, bindingInfo.BindingSource);
    }
示例#5
0
    public void CreateBinder_Caches_NonRootNodes_WhenNonRootNodeReturnsNull()
    {
        // Arrange
        var metadataProvider = new TestModelMetadataProvider();

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

        IModelBinder inner = null;

        var widgetProvider = new TestModelBinderProvider(c =>
        {
            if (c.Metadata.ModelType == typeof(Widget))
            {
                var binder = c.CreateBinder(c.Metadata.Properties[nameof(Widget.Id)]);
                Assert.IsType <NoOpBinder>(binder);
                if (inner == null)
                {
                    inner = binder;
                }
                else
                {
                    Assert.Same(inner, binder);
                }

                return(Mock.Of <IModelBinder>());
            }

            return(null);
        });

        var widgetIdProvider = new TestModelBinderProvider(c =>
        {
            Assert.Equal(typeof(WidgetId), c.Metadata.ModelType);
            return(null);
        });

        options.Value.ModelBinderProviders.Add(widgetProvider);
        options.Value.ModelBinderProviders.Add(widgetIdProvider);

        var factory = new ModelBinderFactory(
            metadataProvider,
            options,
            GetServices());

        var context = new ModelBinderFactoryContext()
        {
            Metadata   = metadataProvider.GetMetadataForType(typeof(Widget)),
            CacheToken = null, // We want the outermost provider to run twice.
        };

        // Act
        var result1 = factory.CreateBinder(context);
        var result2 = factory.CreateBinder(context);

        // Assert
        Assert.NotSame(result1, result2);

        Assert.Equal(2, widgetProvider.SuccessCount);
        Assert.Equal(0, widgetIdProvider.SuccessCount);
    }
示例#6
0
    public void GetBindingInfo_WithAttributesAndModelMetadata_UsesBinderSourceFromModelMetadata_WhenNotFoundViaAttributes()
    {
        // Arrange
        var attributes = new object[]
        {
            new BindPropertyAttribute(),
            new ControllerAttribute(),
            new BindNeverAttribute(),
        };
        var modelType = typeof(Guid);
        var provider  = new TestModelMetadataProvider();

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

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

        // Assert
        Assert.NotNull(bindingInfo);
        Assert.Same(BindingSource.Services, bindingInfo.BindingSource);
    }
        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
            {
                ActionContext = new ActionContext()
                {
                    HttpContext = new DefaultHttpContext()
                    {
                        RequestServices = services.BuildServiceProvider(),
                    }
                },
                ModelMetadata   = modelMetadata,
                ModelName       = "modelName",
                FieldName       = "modelName",
                ModelState      = new ModelStateDictionary(),
                BinderModelName = modelMetadata.BinderModelName,
                BindingSource   = modelMetadata.BindingSource,
                ValidationState = new ValidationStateDictionary(),
            };

            return(bindingContext);
        }
        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);
        }
示例#9
0
    public void EnterNestedScope_FiltersValueProviders_ForValueProviderSource()
    {
        // Arrange
        var metadataProvider = new TestModelMetadataProvider();

        metadataProvider
        .ForProperty(typeof(string), nameof(string.Length))
        .BindingDetails(b => b.BindingSource = BindingSource.Query);

        var original = CreateDefaultValueProvider();
        var context  = DefaultModelBindingContext.CreateBindingContext(
            GetActionContext(),
            original,
            metadataProvider.GetMetadataForType(typeof(string)),
            new BindingInfo(),
            "model");

        var propertyMetadata = metadataProvider.GetMetadataForProperty(typeof(string), nameof(string.Length));

        // Act
        context.EnterNestedScope(propertyMetadata, "Length", "Length", model: null);

        // Assert
        Assert.Collection(
            Assert.IsType <CompositeValueProvider>(context.ValueProvider),
            vp => Assert.Same(original[1], vp));
    }
        private static ModelBindingContext GetBindingContext(Type modelType)
        {
            var metadataProvider = new TestModelMetadataProvider();

            metadataProvider.ForType(modelType).BindingDetails(d => d.BindingSource = BindingSource.Header);
            var modelMetadata  = metadataProvider.GetMetadataForType(modelType);
            var bindingContext = new ModelBindingContext
            {
                ModelMetadata           = modelMetadata,
                ModelName               = "modelName",
                FieldName               = "modelName",
                ModelState              = new ModelStateDictionary(),
                OperationBindingContext = new OperationBindingContext
                {
                    ActionContext = new ActionContext()
                    {
                        HttpContext = new DefaultHttpContext(),
                    },
                    ModelBinder      = new HeaderModelBinder(),
                    MetadataProvider = metadataProvider,
                },
                BinderModelName = modelMetadata.BinderModelName,
                BindingSource   = modelMetadata.BindingSource,
            };

            return(bindingContext);
        }
示例#11
0
        private static ModelBindingContext GetModelBindingContext(bool isReadOnly)
        {
            var metadataProvider = new TestModelMetadataProvider();

            metadataProvider.ForType <List <int> >().BindingDetails(bd => bd.IsReadOnly = isReadOnly);
            var valueProvider = new SimpleHttpValueProvider
            {
                { "someName[0]", new KeyValuePair <int, string>(42, "forty-two") },
                { "someName[1]", new KeyValuePair <int, string>(84, "eighty-four") },
            };

            var bindingContext = new ModelBindingContext
            {
                ModelMetadata           = metadataProvider.GetMetadataForType(typeof(IDictionary <int, string>)),
                ModelName               = "someName",
                ValueProvider           = valueProvider,
                OperationBindingContext = new OperationBindingContext
                {
                    ModelBinder      = CreateKvpBinder(),
                    MetadataProvider = metadataProvider
                }
            };

            return(bindingContext);
        }
示例#12
0
        public async Task ArrayModelBinder_CreatesEmptyCollection_IfIsTopLevelObject()
        {
            // Arrange
            var binder = new ArrayModelBinder <string>(new SimpleTypeModelBinder(typeof(string)));

            var context = CreateContext();

            context.IsTopLevelObject = true;

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

            var metadataProvider = new TestModelMetadataProvider();

            context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(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 <string[]>(result.Model));
            Assert.Equal("modelName", result.Key);
            Assert.True(result.IsModelSet);
        }
        public void AddValidation_CorrectValidationTypeAndOverriddenErrorMessage_WithType()
        {
            // Arrange
            var expectedMessage = "Error message from override.";
            var provider        = new TestModelMetadataProvider();

            provider
            .ForType(typeof(int))
            .BindingDetails(d => d.ModelBindingMessageProvider.SetNonPropertyValueMustBeANumberAccessor(
                                () => $"Error message from override."));
            var metadata = provider.GetMetadataForType(typeof(int));

            var adapter       = new NumericClientModelValidator();
            var actionContext = new ActionContext();
            var context       = new ClientModelValidationContext(actionContext, metadata, provider, new AttributeDictionary());

            // Act
            adapter.AddValidation(context);

            // Assert
            Assert.Collection(
                context.Attributes,
                kvp => { Assert.Equal("data-val", kvp.Key); Assert.Equal("true", kvp.Value); },
                kvp => { Assert.Equal("data-val-number", kvp.Key); Assert.Equal(expectedMessage, kvp.Value); });
        }
        public async Task CollectionModelBinder_DoesNotCreateEmptyCollection_IfModelNonNull()
        {
            // Arrange
            var binder = new CollectionModelBinder <string>(
                new StubModelBinder(result: ModelBindingResult.Failed()),
                NullLoggerFactory.Instance);

            var bindingContext = CreateContext();

            bindingContext.IsTopLevelObject = true;

            var list = new List <string>();

            bindingContext.Model = list;

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

            var metadataProvider = new TestModelMetadataProvider();

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

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

            // Act
            await binder.BindModelAsync(bindingContext);

            // Assert
            Assert.Same(list, bindingContext.Result.Model);
            Assert.Empty(list);
            Assert.True(bindingContext.Result.IsModelSet);
        }
        public async Task BindModel_ReturnsProvidedWhitespaceString_WhenNotConvertEmptyStringToNull(string value)
        {
            // Arrange
            var bindingContext = GetBindingContext(typeof(string));

            bindingContext.ValueProvider = new SimpleValueProvider
            {
                { "theModelName", value }
            };

            var metadataProvider = new TestModelMetadataProvider();

            metadataProvider
            .ForType(typeof(string))
            .DisplayDetails(d => d.ConvertEmptyStringToNull = false);
            bindingContext.ModelMetadata = metadataProvider.GetMetadataForType(typeof(string));

            var binder = new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance);

            // Act
            await binder.BindModelAsync(bindingContext);

            // Assert
            Assert.Same(value, bindingContext.Result.Model);
            Assert.True(bindingContext.ModelState.ContainsKey("theModelName"));
        }
示例#16
0
    public void GetBindingInfo_WithAttributesAndModelMetadata_UsesValuesFromBindingInfo_IfAttributesPresent()
    {
        // Arrange
        var attributes = new object[]
        {
            new ModelBinderAttribute {
                BinderType = typeof(ComplexObjectModelBinder), Name = "Test"
            },
        };
        var modelType = typeof(Guid);
        var provider  = new TestModelMetadataProvider();

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

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

        // Assert
        Assert.NotNull(bindingInfo);
        Assert.Same(typeof(ComplexObjectModelBinder), bindingInfo.BinderType);
        Assert.Same("Test", bindingInfo.BinderModelName);
    }
示例#17
0
    public void GetBindingInfo_WithAttributesAndModelMetadata_UsesPropertyPredicateProviderFromModelMetadata_WhenNotFoundViaAttributes()
    {
        // Arrange
        var attributes = new object[]
        {
            new ModelBinderAttribute(typeof(ComplexObjectModelBinder)),
            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);
    }
示例#18
0
    public void CreateBinder_Caches_WhenTokenIsNotNull()
    {
        // Arrange
        var metadataProvider = new TestModelMetadataProvider();

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

        options.Value.ModelBinderProviders.Add(new TestModelBinderProvider(c =>
        {
            Assert.Equal(typeof(Employee), c.Metadata.ModelType);
            return(Mock.Of <IModelBinder>());
        }));

        var factory = new ModelBinderFactory(
            metadataProvider,
            options,
            GetServices());

        var context = new ModelBinderFactoryContext()
        {
            Metadata   = metadataProvider.GetMetadataForType(typeof(Employee)),
            CacheToken = new object(),
        };

        // Act
        var result1 = factory.CreateBinder(context);
        var result2 = factory.CreateBinder(context);

        // Assert
        Assert.Same(result1, result2);
    }
示例#19
0
        public async Task CollectionModelBinder_DoesNotCreateEmptyCollection_IfModelNonNull()
        {
            // Arrange
            var binder = new CollectionModelBinder <string>(new StubModelBinder(result: null));

            var context = CreateContext();

            context.IsTopLevelObject = true;

            var list = new List <string>();

            context.Model = list;

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

            var metadataProvider = new TestModelMetadataProvider();

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

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

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

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

            Assert.Same(list, result.Model);
            Assert.Empty(list);
            Assert.Equal("modelName", result.Key);
            Assert.True(result.IsModelSet);
        }
示例#20
0
    public void CreateBinder_CreatesNoOpBinder_WhenPropertyDoesntHaveABinder()
    {
        // Arrange
        var metadataProvider = new TestModelMetadataProvider();

        // There isn't a provider that can handle WidgetId.
        var options = Options.Create(new MvcOptions());

        options.Value.ModelBinderProviders.Add(new TestModelBinderProvider(c =>
        {
            if (c.Metadata.ModelType == typeof(Widget))
            {
                Assert.NotNull(c.CreateBinder(c.Metadata.Properties[nameof(Widget.Id)]));
                return(Mock.Of <IModelBinder>());
            }

            return(null);
        }));

        var factory = new ModelBinderFactory(
            metadataProvider,
            options,
            GetServices());

        var context = new ModelBinderFactoryContext()
        {
            Metadata = metadataProvider.GetMetadataForType(typeof(Widget)),
        };

        // Act
        var result = factory.CreateBinder(context);

        // Assert
        Assert.NotNull(result);
    }
示例#21
0
    public async Task KeyValuePairModelBinder_CreatesEmptyCollection_IfIsTopLevelObject()
    {
        // Arrange
        var binder = new KeyValuePairModelBinder <string, string>(
            new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
            new SimpleTypeModelBinder(typeof(string), NullLoggerFactory.Instance),
            NullLoggerFactory.Instance);

        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(KeyValuePair <string, string>));

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

        // Act
        await binder.BindModelAsync(bindingContext);

        // Assert
        var model = Assert.IsType <KeyValuePair <string, string> >(bindingContext.Result.Model);

        Assert.Equal(default(KeyValuePair <string, string>), model);
        Assert.True(bindingContext.Result.IsModelSet);
    }
示例#22
0
        private static ModelMetadata GetMetadataForType(Type modelType)
        {
            var metadataProvider = new TestModelMetadataProvider();

            metadataProvider.ForType(modelType).BindingDetails(d => d.BindingSource = BindingSource.Header);
            return(metadataProvider.GetMetadataForType(modelType));
        }
示例#23
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
            {
                ActionContext = new ActionContext()
                {
                    HttpContext = new DefaultHttpContext()
                    {
                        RequestServices = services.BuildServiceProvider(),
                    }
                },
                ModelMetadata = modelMetadata,
                ModelName = "modelName",
                FieldName = "modelName",
                ModelState = new ModelStateDictionary(),
                BinderModelName = modelMetadata.BinderModelName,
                BindingSource = modelMetadata.BindingSource,
                ValidationState = new ValidationStateDictionary(),
            };

            return bindingContext;
        }
        public async Task BindModelAsync_PassesExpectedBindingInfoAndMetadata_IfPrefixDoesNotMatch(
            BindingInfo parameterBindingInfo,
            string metadataBinderModelName,
            string parameterName,
            string expectedModelName)
        {
            // Arrange
            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(TaskCache.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) =>
            {
                // 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 argumentBinder = new DefaultControllerArgumentBinder(
                metadataProvider,
                factory.Object,
                CreateMockValidator());

            var controllerContext = GetControllerContext();

            controllerContext.ActionDescriptor.Parameters.Add(parameterDescriptor);

            // Act & Assert
            await argumentBinder.BindModelAsync(parameterDescriptor, controllerContext);
        }
示例#25
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);
        });
    }
示例#26
0
        private static DefaultModelBindingContext GetBindingContext(Type modelType)
        {
            var metadataProvider = new TestModelMetadataProvider();

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

            return(GetBindingContext(metadataProvider, modelMetadata));
        }
        public async Task BindModelAsync_PassesExpectedBindingInfoAndMetadata_IfPrefixMatches()
        {
            // Arrange
            var expectedModelName = "expectedName";

            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(TaskCache.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) =>
            {
                // 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 DefaultControllerArgumentBinder(
                metadataProvider,
                factory.Object,
                CreateMockValidator());

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

            var controllerContext = GetControllerContext();

            controllerContext.ActionDescriptor.Parameters.Add(parameterDescriptor);
            controllerContext.ValueProviderFactories.Insert(0, valueProviderFactory);

            // Act & Assert
            await argumentBinder.BindModelAsync(parameterDescriptor, controllerContext);
        }
示例#28
0
    public void CreateBinder_Caches_NonRootNodes_UsesModelMetadataAsToken()
    {
        // Arrange
        var metadataProvider = new TestModelMetadataProvider();

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

        IModelBinder inner = null;

        var widgetProvider = new TestModelBinderProvider(c =>
        {
            if (c.Metadata.ModelType == typeof(Widget))
            {
                inner = c.CreateBinder(c.Metadata.Properties[nameof(Widget.Id)]);
                return(Mock.Of <IModelBinder>());
            }

            return(null);
        });

        var widgetIdProvider = new TestModelBinderProvider(c =>
        {
            Assert.Equal(typeof(WidgetId), c.Metadata.ModelType);
            return(Mock.Of <IModelBinder>());
        });

        options.Value.ModelBinderProviders.Add(widgetProvider);
        options.Value.ModelBinderProviders.Add(widgetIdProvider);

        var factory = new ModelBinderFactory(
            metadataProvider,
            options,
            GetServices());

        var context = new ModelBinderFactoryContext()
        {
            Metadata   = metadataProvider.GetMetadataForType(typeof(Widget)),
            CacheToken = null,
        };

        // Act 1
        var result1 = factory.CreateBinder(context);

        context.Metadata   = context.Metadata.Properties[nameof(Widget.Id)];
        context.CacheToken = context.Metadata;

        // Act 2
        var result2 = factory.CreateBinder(context);

        // Assert
        Assert.Same(inner, result2);
        Assert.Equal(1, widgetProvider.SuccessCount);
        Assert.Equal(1, widgetIdProvider.SuccessCount);
    }
示例#29
0
        public void GetTemplateNames_WithNoRegression(Type fieldType)
        {
            // Arrange
            var metadata = _metadataProvider.GetMetadataForType(fieldType);
            var expected = TemplateRenderer.GetTypeNames(metadata, metadata.UnderlyingOrModelType);

            // Act
            var actual = _templateNameSource.GetTemplateNames(metadata);

            // Assert
            actual.Should().BeEquivalentTo(expected, cfg => cfg.WithStrictOrdering());
        }
示例#30
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);
    }
示例#31
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);
    }
示例#32
0
        public void GetTypeNames_ReturnsExpectedResults(Type fieldType, string[] expectedResult)
        {
            // Arrange
            var metadataProvider = new TestModelMetadataProvider();
            var metadata = metadataProvider.GetMetadataForType(fieldType);

            // Act
            var typeNames = TemplateRenderer.GetTypeNames(metadata, fieldType);

            // Assert
            var collectionAssertions = expectedResult.Select<string, Action<string>>(expected =>
                actual => Assert.Equal(expected, actual));
            Assert.Collection(typeNames, collectionAssertions.ToArray());
        }
        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 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.BindingSource, bindingContext.BindingSource);
            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();
        }
        public async Task CanCreateModel_ReturnsTrue_IfIsTopLevelObjectAndNotIsFirstChanceBinding(
            bool isTopLevelObject,
            bool isFirstChanceBinding,
            string binderModelName,
            string modelName,
            bool expectedCanCreate)
        {
            var mockValueProvider = new Mock<IValueProvider>();
            mockValueProvider
                .Setup(o => o.ContainsPrefixAsync(It.IsAny<string>()))
                .Returns(Task.FromResult(false));

            var metadataProvider = new TestModelMetadataProvider();
            var bindingContext = new MutableObjectBinderContext
            {
                ModelBindingContext = new ModelBindingContext
                {
                    IsTopLevelObject = isTopLevelObject,
                    IsFirstChanceBinding = isFirstChanceBinding,

                    // Random type.
                    ModelMetadata = metadataProvider.GetMetadataForType(typeof(Person)),
                    ValueProvider = mockValueProvider.Object,
                    OperationBindingContext = new OperationBindingContext
                    {
                        ValueProvider = mockValueProvider.Object,
                        MetadataProvider = metadataProvider,
                        ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
                    },

                    // CanCreateModel() ignores the BinderModelName and ModelName properties.
                    BinderModelName = binderModelName,
                    ModelName = modelName,
                },
            };

            var mutableBinder = new TestableMutableObjectModelBinder();
            bindingContext.PropertyMetadata =
                mutableBinder.GetMetadataForProperties(bindingContext.ModelBindingContext).ToArray();

            // Act
            var canCreate = await mutableBinder.CanCreateModel(bindingContext);

            // Assert
            Assert.Equal(expectedCanCreate, canCreate);
        }
示例#35
0
        public void CreateChildBindingContext_CopiesProperties()
        {
            // Arrange
            var originalBindingContext = new ModelBindingContext
            {
                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 newBindingContext = ModelBindingContext.CreateChildBindingContext(
                originalBindingContext,
                newModelMetadata,
                fieldName: "fieldName",
                modelName: "modelprefix.fieldName",
                model: null);

            // Assert
            Assert.Same(newModelMetadata.BinderModelName, newBindingContext.BinderModelName);
            Assert.Same(newModelMetadata.BinderType, newBindingContext.BinderType);
            Assert.Same(newModelMetadata.BindingSource, newBindingContext.BindingSource);
            Assert.False(newBindingContext.FallbackToEmptyPrefix);
            Assert.Equal("fieldName", newBindingContext.FieldName);
            Assert.False(newBindingContext.IsTopLevelObject);
            Assert.Null(newBindingContext.Model);
            Assert.Same(newModelMetadata, newBindingContext.ModelMetadata);
            Assert.Equal("modelprefix.fieldName", newBindingContext.ModelName);
            Assert.Same(originalBindingContext.ModelState, newBindingContext.ModelState);
            Assert.Same(originalBindingContext.OperationBindingContext, newBindingContext.OperationBindingContext);
            Assert.Same(originalBindingContext.ValueProvider, newBindingContext.ValueProvider);
        }
        public async Task BindingSourceModelBinder_ReturnsFalse_NonMatchingSource()
        {
            // Arrange
            var provider = new TestModelMetadataProvider();
            provider.ForType<string>().BindingDetails(d => d.BindingSource = BindingSource.Query);

            var context = new ModelBindingContext();
            context.ModelMetadata = provider.GetMetadataForType(typeof(string));

            var binder = new TestableBindingSourceModelBinder(BindingSource.Body);

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

            // Assert
            Assert.Null(result);
            Assert.False(binder.WasBindModelCoreCalled);
        }
        public void CreateBindingContext_FiltersValueProviders_ForValueProviderSource()
        {
            // Arrange
            var metadataProvider = new TestModelMetadataProvider();

            var original = CreateDefaultValueProvider();

            // Act
            var context = DefaultModelBindingContext.CreateBindingContext(
                new ActionContext(),
                original,
                metadataProvider.GetMetadataForType(typeof(object)),
                new BindingInfo() { BindingSource = BindingSource.Query },
                "model");

            // Assert
            Assert.Collection(
                Assert.IsType<CompositeValueProvider>(context.ValueProvider),
                vp => Assert.Same(original[1], vp));
        }
        private static ModelBindingContext GetBindingContext(Type modelType)
        {
            var metadataProvider = new TestModelMetadataProvider();
            metadataProvider.ForType(modelType).BindingDetails(d => d.BindingSource = BindingSource.Header);
            var modelMetadata = metadataProvider.GetMetadataForType(modelType);
            var bindingContext = new ModelBindingContext
            {
                ModelMetadata = modelMetadata,
                ModelName = "modelName",
                OperationBindingContext = new OperationBindingContext
                {
                    ModelBinder = new HeaderModelBinder(),
                    MetadataProvider = metadataProvider,
                    HttpContext = new DefaultHttpContext()
                },
                BinderModelName = modelMetadata.BinderModelName,
                BindingSource = modelMetadata.BindingSource,
            };

            return bindingContext;
        }
        public void CanCreateModel_ReturnsTrue_IfIsTopLevelObject(
            bool isTopLevelObject,
            bool expectedCanCreate)
        {
            var mockValueProvider = new Mock<IValueProvider>();
            mockValueProvider
                .Setup(o => o.ContainsPrefix(It.IsAny<string>()))
                .Returns(false);

            var metadataProvider = new TestModelMetadataProvider();
            var bindingContext = new MutableObjectBinderContext
            {
                ModelBindingContext = new ModelBindingContext
                {
                    IsTopLevelObject = isTopLevelObject,

                    // Random type.
                    ModelMetadata = metadataProvider.GetMetadataForType(typeof(Person)),
                    ValueProvider = mockValueProvider.Object,
                    OperationBindingContext = new OperationBindingContext
                    {
                        ValueProvider = mockValueProvider.Object,
                        MetadataProvider = metadataProvider,
                        ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
                    },
                    ModelState = new ModelStateDictionary(),
                },
            };

            var mutableBinder = new TestableMutableObjectModelBinder();
            bindingContext.PropertyMetadata =
                mutableBinder.GetMetadataForProperties(bindingContext.ModelBindingContext).ToArray();

            // Act
            var canCreate = mutableBinder.CanCreateModel(bindingContext);

            // Assert
            Assert.Equal(expectedCanCreate, canCreate);
        }
        public async Task CanCreateModel_CreatesModel_ForTopLevelObjectIfThereIsExplicitPrefix(
            Type modelType,
            bool isPrefixProvided)
        {
            var mockValueProvider = new Mock<IValueProvider>();
            mockValueProvider.Setup(o => o.ContainsPrefixAsync(It.IsAny<string>()))
                             .Returns(Task.FromResult(false));

            var metadataProvider = new TestModelMetadataProvider();
            var bindingContext = new MutableObjectBinderContext
            {
                ModelBindingContext = new ModelBindingContext
                {
                    // Random type.
                    ModelMetadata = metadataProvider.GetMetadataForType(typeof(Person)),
                    ValueProvider = mockValueProvider.Object,
                    OperationBindingContext = new OperationBindingContext
                    {
                        ValueProvider = mockValueProvider.Object,
                        MetadataProvider = metadataProvider,
                        ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
                    },

                    // Setting it to empty ensures that model does not get created becasue of no model name.
                    ModelName = "dummyModelName",
                    BinderModelName = isPrefixProvided ? "prefix" : null,
                }
            };

            var mutableBinder = new TestableMutableObjectModelBinder();
            bindingContext.PropertyMetadata = mutableBinder.GetMetadataForProperties(
                                                                bindingContext.ModelBindingContext);

            // Act
            var retModel = await mutableBinder.CanCreateModel(bindingContext);

            // Assert
            Assert.Equal(isPrefixProvided, retModel);
        }
示例#41
0
        public async Task ArrayModelBinder_CreatesEmptyCollection_IfIsTopLevelObject()
        {
            // Arrange
            var binder = new ArrayModelBinder<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(string[]));

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

            // Act
            await binder.BindModelAsync(bindingContext);

            // Assert
            Assert.Empty(Assert.IsType<string[]>(bindingContext.Result.Model));
            Assert.True(bindingContext.Result.IsModelSet);
        }
        public async Task BindingSourceModelBinder_ReturnsTrue_MatchingSource()
        {
            // Arrange
            var provider = new TestModelMetadataProvider();
            provider.ForType<string>().BindingDetails(d => d.BindingSource = BindingSource.Body);
            var modelMetadata = provider.GetMetadataForType(typeof(string));
            var context = new ModelBindingContext()
            {
                ModelMetadata = modelMetadata,
                BindingSource = modelMetadata.BindingSource,
                BinderModelName = modelMetadata.BinderModelName
            };

            var binder = new TestableBindingSourceModelBinder(BindingSource.Body);

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

            // Assert
            Assert.NotNull(result);
            Assert.True(result.IsModelSet);
            Assert.True(binder.WasBindModelCoreCalled);
        }
        public void GetChildModelBindingContext()
        {
            // Arrange
            var originalBindingContext = new ModelBindingContext
            {
                ModelMetadata = new TestModelMetadataProvider().GetMetadataForType(typeof(object)),
                ModelName = "theName",
                ModelState = new ModelStateDictionary(),
                ValueProvider = new SimpleHttpValueProvider()
            };

            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 newBindingContext = ModelBindingContext.GetChildModelBindingContext(
                originalBindingContext,
                string.Empty,
                newModelMetadata);

            // Assert
            Assert.Same(newModelMetadata, newBindingContext.ModelMetadata);
            Assert.Same(newModelMetadata.BindingSource, newBindingContext.BindingSource);
            Assert.Same(newModelMetadata.BinderModelName, newBindingContext.BinderModelName);
            Assert.Same(newModelMetadata.BinderType, newBindingContext.BinderType);
            Assert.Equal("", newBindingContext.ModelName);
            Assert.Equal(originalBindingContext.ModelState, newBindingContext.ModelState);
            Assert.Equal(originalBindingContext.ValueProvider, newBindingContext.ValueProvider);
        }
示例#44
0
        private static ModelBindingContext GetModelBindingContext(bool isReadOnly)
        {
            var metadataProvider = new TestModelMetadataProvider();
            metadataProvider.ForType<List<int>>().BindingDetails(bd => bd.IsReadOnly = isReadOnly);
            var valueProvider = new SimpleHttpValueProvider
            {
                { "someName[0]", new KeyValuePair<int, string>(42, "forty-two") },
                { "someName[1]", new KeyValuePair<int, string>(84, "eighty-four") },
            };

            var bindingContext = new ModelBindingContext
            {
                ModelMetadata = metadataProvider.GetMetadataForType(typeof(IDictionary<int, string>)),
                ModelName = "someName",
                ValueProvider = valueProvider,
                OperationBindingContext = new OperationBindingContext
                {
                    ModelBinder = CreateKvpBinder(),
                    MetadataProvider = metadataProvider
                }
            };

            return bindingContext;
        }
示例#45
0
        public void CreateBinder_CreatesNoOpBinder_WhenPropertyDoesntHaveABinder()
        {
            // Arrange
            var metadataProvider = new TestModelMetadataProvider();

            // There isn't a provider that can handle WidgetId.
            var options = new TestOptionsManager<MvcOptions>();
            options.Value.ModelBinderProviders.Add(new TestModelBinderProvider(c =>
            {
                if (c.Metadata.ModelType == typeof(Widget))
                {
                    Assert.NotNull(c.CreateBinder(c.Metadata.Properties[nameof(Widget.Id)]));
                    return Mock.Of<IModelBinder>();
                }

                return null;
            }));

            var factory = new ModelBinderFactory(metadataProvider, options);

            var context = new ModelBinderFactoryContext()
            {
                Metadata = metadataProvider.GetMetadataForType(typeof(Widget)),
            };

            // Act
            var result = factory.CreateBinder(context);

            // Assert
            Assert.NotNull(result);
        }
示例#46
0
        public async Task ProcessAsync_GeneratesExpectedOutput(
            object model,
            Type containerType,
            Func<object> modelAccessor,
            string propertyPath,
            TagHelperOutputContent tagHelperOutputContent)
        {
            // Arrange
            var expectedTagName = "not-label";
            var expectedAttributes = new TagHelperAttributeList
            {
                { "class", "form-control" },
                { "for", tagHelperOutputContent.ExpectedId }
            };
            var metadataProvider = new TestModelMetadataProvider();

            var containerMetadata = metadataProvider.GetMetadataForType(containerType);
            var containerExplorer = metadataProvider.GetModelExplorerForType(containerType, model);

            var propertyMetadata = metadataProvider.GetMetadataForProperty(containerType, "Text");
            var modelExplorer = containerExplorer.GetExplorerForExpression(propertyMetadata, modelAccessor());
            var htmlGenerator = new TestableHtmlGenerator(metadataProvider);

            var modelExpression = new ModelExpression(propertyPath, modelExplorer);
            var tagHelper = new LabelTagHelper(htmlGenerator)
            {
                For = modelExpression,
            };
            var expectedPreContent = "original pre-content";
            var expectedPostContent = "original post-content";

            var tagHelperContext = new TagHelperContext(
                allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
                    Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
                items: new Dictionary<object, object>(),
                uniqueId: "test",
                getChildContentAsync: useCachedResult =>
                {
                    var tagHelperContent = new DefaultTagHelperContent();
                    tagHelperContent.SetContent(tagHelperOutputContent.OriginalChildContent);
                    return Task.FromResult<TagHelperContent>(tagHelperContent);
                });
            var htmlAttributes = new TagHelperAttributeList
            {
                { "class", "form-control" },
            };
            var output = new TagHelperOutput(expectedTagName, htmlAttributes);
            output.PreContent.SetContent(expectedPreContent);
            output.PostContent.SetContent(expectedPostContent);

            // LabelTagHelper checks IsContentModified so we don't want to forcibly set it if
            // tagHelperOutputContent.OriginalContent is going to be null or empty.
            if (!string.IsNullOrEmpty(tagHelperOutputContent.OriginalContent))
            {
                output.Content.SetContent(tagHelperOutputContent.OriginalContent);
            }

            var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider);
            tagHelper.ViewContext = viewContext;

            // Act
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            Assert.Equal(expectedAttributes, output.Attributes);
            Assert.Equal(expectedPreContent, output.PreContent.GetContent());
            Assert.Equal(
                tagHelperOutputContent.ExpectedContent,
                HtmlContentUtilities.HtmlContentToString(output.Content));
            Assert.Equal(expectedPostContent, output.PostContent.GetContent());
            Assert.Equal(TagMode.StartTagAndEndTag, output.TagMode);
            Assert.Equal(expectedTagName, output.TagName);
        }
示例#47
0
        public async Task ProcessAsyncInTemplate_WithItems_GeneratesExpectedOutput_DoesNotChangeSelectList(
            object model,
            Type containerType,
            Func<object> modelAccessor,
            NameAndId nameAndId,
            string expectedOptions)
        {
            // Arrange
            var originalAttributes = new Dictionary<string, object>
            {
                { "class", "form-control" },
            };
            var originalPostContent = "original content";

            var expectedAttributes = new Dictionary<string, object>(originalAttributes)
            {
                { "id", nameAndId.Id },
                { "name", nameAndId.Name },
                { "valid", "from validation attributes" },
            };
            var expectedPreContent = "original pre-content";
            var expectedContent = "original content";
            var expectedPostContent = originalPostContent + expectedOptions;
            var expectedTagName = "select";

            var metadataProvider = new TestModelMetadataProvider();

            var containerMetadata = metadataProvider.GetMetadataForType(containerType);
            var containerExplorer = metadataProvider.GetModelExplorerForType(containerType, model);

            var propertyMetadata = metadataProvider.GetMetadataForProperty(containerType, "Text");
            var modelExplorer = containerExplorer.GetExplorerForExpression(propertyMetadata, modelAccessor());

            var modelExpression = new ModelExpression(name: string.Empty, modelExplorer: modelExplorer);

            var tagHelperContext = new TagHelperContext(
                allAttributes: new Dictionary<string, object>(),
                items: new Dictionary<object, object>(),
                uniqueId: "test",
                getChildContentAsync: () =>
                {
                    var tagHelperContent = new DefaultTagHelperContent();
                    tagHelperContent.SetContent("Something");
                    return Task.FromResult<TagHelperContent>(tagHelperContent);
                });
            var output = new TagHelperOutput(expectedTagName, originalAttributes)
            {
                SelfClosing = true
            };
            output.PreContent.SetContent(expectedPreContent);
            output.Content.SetContent(expectedContent);
            output.PostContent.SetContent(originalPostContent);

            var htmlGenerator = new TestableHtmlGenerator(metadataProvider)
            {
                ValidationAttributes =
                {
                    {  "valid", "from validation attributes" },
                }
            };
            var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider);
            viewContext.ViewData.TemplateInfo.HtmlFieldPrefix = nameAndId.Name;

            var items = new SelectList(new[] { "", "outer text", "inner text", "other text" });
            var savedDisabled = items.Select(item => item.Disabled).ToList();
            var savedGroup = items.Select(item => item.Group).ToList();
            var savedSelected = items.Select(item => item.Selected).ToList();
            var savedText = items.Select(item => item.Text).ToList();
            var savedValue = items.Select(item => item.Value).ToList();
            var tagHelper = new SelectTagHelper
            {
                For = modelExpression,
                Generator = htmlGenerator,
                Items = items,
                ViewContext = viewContext,
            };

            // Act
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            Assert.True(output.SelfClosing);
            Assert.Equal(expectedAttributes, output.Attributes);
            Assert.Equal(expectedPreContent, output.PreContent.GetContent());
            Assert.Equal(expectedContent, output.Content.GetContent());
            Assert.Equal(expectedPostContent, output.PostContent.GetContent());
            Assert.Equal(expectedTagName, output.TagName);

            Assert.NotNull(viewContext.FormContext?.FormData);
            Assert.Single(
                viewContext.FormContext.FormData,
                entry => entry.Key == SelectTagHelper.SelectedValuesFormDataKey);

            Assert.Equal(savedDisabled, items.Select(item => item.Disabled));
            Assert.Equal(savedGroup, items.Select(item => item.Group));
            Assert.Equal(savedSelected, items.Select(item => item.Selected));
            Assert.Equal(savedText, items.Select(item => item.Text));
            Assert.Equal(savedValue, items.Select(item => item.Value));
        }
示例#48
0
        public async Task ProcessAsync_GeneratesExpectedOutput(
            object model,
            Type containerType,
            Func<object> modelAccessor,
            NameAndId nameAndId,
            string ignored)
        {
            // Arrange
            var originalAttributes = new Dictionary<string, object>
            {
                { "class", "form-control" },
            };
            var originalPostContent = "original content";

            var expectedAttributes = new Dictionary<string, object>(originalAttributes)
            {
                { "id", nameAndId.Id },
                { "name", nameAndId.Name },
                { "valid", "from validation attributes" },
            };
            var expectedPreContent = "original pre-content";
            var expectedContent = "original content";
            var expectedPostContent = originalPostContent;
            var expectedTagName = "not-select";

            var metadataProvider = new TestModelMetadataProvider();
            var containerMetadata = metadataProvider.GetMetadataForType(containerType);
            var containerExplorer = metadataProvider.GetModelExplorerForType(containerType, model);

            var propertyMetadata = metadataProvider.GetMetadataForProperty(containerType, "Text");
            var modelExplorer = containerExplorer.GetExplorerForExpression(propertyMetadata, modelAccessor());

            var modelExpression = new ModelExpression(nameAndId.Name, modelExplorer);

            var tagHelperContext = new TagHelperContext(
                allAttributes: new Dictionary<string, object>(),
                items: new Dictionary<object, object>(),
                uniqueId: "test",
                getChildContentAsync: () =>
                {
                    var tagHelperContent = new DefaultTagHelperContent();
                    tagHelperContent.SetContent("Something");
                    return Task.FromResult<TagHelperContent>(tagHelperContent);
                });
            var output = new TagHelperOutput(expectedTagName, originalAttributes)
            {
                SelfClosing = true,
            };
            output.PreContent.SetContent(expectedPreContent);
            output.Content.SetContent(expectedContent);
            output.PostContent.SetContent(originalPostContent);

            var htmlGenerator = new TestableHtmlGenerator(metadataProvider)
            {
                ValidationAttributes =
                {
                    {  "valid", "from validation attributes" },
                }
            };
            var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider);
            var tagHelper = new SelectTagHelper
            {
                For = modelExpression,
                Generator = htmlGenerator,
                ViewContext = viewContext,
            };

            // Act
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            Assert.True(output.SelfClosing);
            Assert.Equal(expectedAttributes, output.Attributes);
            Assert.Equal(expectedPreContent, output.PreContent.GetContent());
            Assert.Equal(expectedContent, output.Content.GetContent());
            Assert.Equal(expectedPostContent, output.PostContent.GetContent());
            Assert.Equal(expectedTagName, output.TagName);

            Assert.NotNull(viewContext.FormContext?.FormData);
            Assert.Single(
                viewContext.FormContext.FormData,
                entry => entry.Key == SelectTagHelper.SelectedValuesFormDataKey);
        }
示例#49
0
        public void CreateBinder_Throws_WhenBinderNotCreated()
        {
            // Arrange
            var metadataProvider = new TestModelMetadataProvider();
            var options = new TestOptionsManager<MvcOptions>();
            var factory = new ModelBinderFactory(metadataProvider, options);

            var context = new ModelBinderFactoryContext()
            {
                Metadata = metadataProvider.GetMetadataForType(typeof(string)),
            };

            // Act
            var exception = Assert.Throws<InvalidOperationException>(() => factory.CreateBinder(context));

            // Assert
            Assert.Equal(
                $"Could not create a model binder for model object of type '{typeof(string).FullName}'.",
                exception.Message);
        }
示例#50
0
 private static DefaultModelBindingContext GetBindingContext(
     IValueProvider valueProvider,
     Type keyValuePairType)
 {
     var metadataProvider = new TestModelMetadataProvider();
     var bindingContext = new DefaultModelBindingContext
     {
         ModelMetadata = metadataProvider.GetMetadataForType(keyValuePairType),
         ModelName = "someName",
         ModelState = new ModelStateDictionary(),
         ValueProvider = valueProvider,
     };
     return bindingContext;
 }
示例#51
0
        private static ModelBindingContext GetBindingContext(
            IValueProvider valueProvider,
            bool isReadOnly = false)
        {
            var metadataProvider = new TestModelMetadataProvider();
            metadataProvider.ForType<int[]>().BindingDetails(bd => bd.IsReadOnly = isReadOnly);

            var bindingContext = new ModelBindingContext
            {
                ModelMetadata = metadataProvider.GetMetadataForType(typeof(int[])),
                ModelName = "someName",
                ValueProvider = valueProvider,
                OperationBindingContext = new OperationBindingContext
                {
                    ModelBinder = CreateIntBinder(),
                    MetadataProvider = metadataProvider
                },
            };
            return bindingContext;
        }
示例#52
0
        public void CreateBinder_NestedProperties()
        {
            // Arrange
            var metadataProvider = new TestModelMetadataProvider();

            var options = new TestOptionsManager<MvcOptions>();
            options.Value.ModelBinderProviders.Add(new TestModelBinderProvider(c =>
            {
                if (c.Metadata.ModelType == typeof(Widget))
                {
                    Assert.NotNull(c.CreateBinder(c.Metadata.Properties[nameof(Widget.Id)]));
                    return Mock.Of<IModelBinder>();
                }
                else if (c.Metadata.ModelType == typeof(WidgetId))
                {
                    return Mock.Of<IModelBinder>();
                }

                return null;
            }));

            var factory = new ModelBinderFactory(metadataProvider, options);

            var context = new ModelBinderFactoryContext()
            {
                Metadata = metadataProvider.GetMetadataForType(typeof(Widget)),
            };

            // Act
            var result = factory.CreateBinder(context);

            // Assert
            Assert.NotNull(result);
        }
示例#53
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 = new TestOptionsManager<MvcOptions>();
            options.Value.ModelBinderProviders.Insert(0, modelBinderProvider);

            var factory = new ModelBinderFactory(metadataProvider, options);
            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 void EnterNestedScope_FiltersValueProviders_BasedOnTopLevelValueProviders()
        {
            // Arrange
            var metadataProvider = new TestModelMetadataProvider();
            metadataProvider
                .ForProperty(typeof(string), nameof(string.Length))
                .BindingDetails(b => b.BindingSource = BindingSource.Form);

            var original = CreateDefaultValueProvider();

            var context = DefaultModelBindingContext.CreateBindingContext(
                new ActionContext(),
                original,
                metadataProvider.GetMetadataForType(typeof(string)),
                new BindingInfo() { BindingSource = BindingSource.Query },
                "model");

            var propertyMetadata = metadataProvider.GetMetadataForProperty(typeof(string), nameof(string.Length));

            // Act
            context.EnterNestedScope(propertyMetadata, "Length", "Length", model: null);

            // Assert
            Assert.Collection(
                Assert.IsType<CompositeValueProvider>(context.ValueProvider),
                vp => Assert.Same(original[2], vp));
        }
示例#55
0
        public void CreateBinder_Caches_NonRootNodes_WhenNonRootNodeReturnsNull()
        {
            // Arrange
            var metadataProvider = new TestModelMetadataProvider();

            var options = new TestOptionsManager<MvcOptions>();

            IModelBinder inner = null;

            var widgetProvider = new TestModelBinderProvider(c =>
            {
                if (c.Metadata.ModelType == typeof(Widget))
                {
                    var binder = c.CreateBinder(c.Metadata.Properties[nameof(Widget.Id)]);
                    Assert.IsType<NoOpBinder>(binder);
                    if (inner == null)
                    {
                        inner = binder;
                    }
                    else
                    {
                        Assert.Same(inner, binder);
                    }

                    return Mock.Of<IModelBinder>();
                }

                return null;
            });

            var widgetIdProvider = new TestModelBinderProvider(c =>
            {
                Assert.Equal(typeof(WidgetId), c.Metadata.ModelType);
                return null;
            });

            options.Value.ModelBinderProviders.Add(widgetProvider);
            options.Value.ModelBinderProviders.Add(widgetIdProvider);

            var factory = new ModelBinderFactory(metadataProvider, options);

            var context = new ModelBinderFactoryContext()
            {
                Metadata = metadataProvider.GetMetadataForType(typeof(Widget)),
                CacheToken = null, // We want the outermost provider to run twice.
            };

            // Act
            var result1 = factory.CreateBinder(context);
            var result2 = factory.CreateBinder(context);

            // Assert
            Assert.NotSame(result1, result2);

            Assert.Equal(2, widgetProvider.SuccessCount);
            Assert.Equal(0, widgetIdProvider.SuccessCount);
        }
示例#56
0
        public async Task Process_GeneratesExpectedOutput(
            object container,
            Type containerType,
            object model,
            NameAndId nameAndId,
            string expectedContent)
        {
            // Arrange
            var expectedAttributes = new TagHelperAttributeList
            {
                { "class", "form-control" },
                { "id", nameAndId.Id },
                { "name", nameAndId.Name },
                {  "valid", "from validation attributes" },
            };
            var expectedTagName = "not-textarea";

            var metadataProvider = new TestModelMetadataProvider();

            var containerMetadata = metadataProvider.GetMetadataForType(containerType);
            var containerExplorer = metadataProvider.GetModelExplorerForType(containerType, container);

            var propertyMetadata = metadataProvider.GetMetadataForProperty(containerType, "Text");
            var modelExplorer = containerExplorer.GetExplorerForExpression(propertyMetadata, model);

            var htmlGenerator = new TestableHtmlGenerator(metadataProvider)
            {
                ValidationAttributes =
                {
                    {  "valid", "from validation attributes" },
                }
            };

            // Property name is either nameof(Model.Text) or nameof(NestedModel.Text).
            var modelExpression = new ModelExpression(nameAndId.Name, modelExplorer);
            var tagHelper = new TextAreaTagHelper(htmlGenerator)
            {
                For = modelExpression,
            };

            var tagHelperContext = new TagHelperContext(
                allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
                    Enumerable.Empty<IReadOnlyTagHelperAttribute>()),
                items: new Dictionary<object, object>(),
                uniqueId: "test",
                getChildContentAsync: useCachedResult =>
                {
                    var tagHelperContent = new DefaultTagHelperContent();
                    tagHelperContent.SetContent("Something");
                    return Task.FromResult<TagHelperContent>(tagHelperContent);
                });
            var htmlAttributes = new TagHelperAttributeList
            {
                { "class", "form-control" },
            };
            var output = new TagHelperOutput(expectedTagName, htmlAttributes)
            {
                TagMode = TagMode.SelfClosing,
            };
            output.Content.SetContent("original content");

            var viewContext = TestableHtmlGenerator.GetViewContext(model, htmlGenerator, metadataProvider);
            tagHelper.ViewContext = viewContext;

            // Act
            await tagHelper.ProcessAsync(tagHelperContext, output);

            // Assert
            Assert.Equal(TagMode.SelfClosing, output.TagMode);
            Assert.Equal(expectedAttributes, output.Attributes);
            Assert.Equal(expectedContent, HtmlContentUtilities.HtmlContentToString(output.Content));
            Assert.Equal(expectedTagName, output.TagName);
        }
示例#57
0
        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));
        }
示例#58
0
        public void CreateBinder_BreaksCycles()
        {
            // Arrange
            var metadataProvider = new TestModelMetadataProvider();

            var callCount = 0;

            var options = new TestOptionsManager<MvcOptions>();
            options.Value.ModelBinderProviders.Add(new TestModelBinderProvider(c =>
            {
                var currentCallCount = ++callCount;
                Assert.Equal(typeof(Employee), c.Metadata.ModelType);
                var binder = c.CreateBinder(c.Metadata.Properties[nameof(Employee.Manager)]);

                if (currentCallCount == 2)
                {
                    Assert.IsType<PlaceholderBinder>(binder);
                }

                return Mock.Of<IModelBinder>();
            }));

            var factory = new ModelBinderFactory(metadataProvider, options);

            var context = new ModelBinderFactoryContext()
            {
                Metadata = metadataProvider.GetMetadataForType(typeof(Employee)),
            };

            // Act
            var result = factory.CreateBinder(context);

            // Assert
            Assert.NotNull(result);
        }
示例#59
0
        public void CreateBinder_DoesNotCache_WhenTokenIsNull()
        {
            // Arrange
            var metadataProvider = new TestModelMetadataProvider();

            var options = new TestOptionsManager<MvcOptions>();
            options.Value.ModelBinderProviders.Add(new TestModelBinderProvider(c =>
            {
                Assert.Equal(typeof(Employee), c.Metadata.ModelType);
                return Mock.Of<IModelBinder>();
            }));

            var factory = new ModelBinderFactory(metadataProvider, options);

            var context = new ModelBinderFactoryContext()
            {
                Metadata = metadataProvider.GetMetadataForType(typeof(Employee)),
            };

            // Act
            var result1 = factory.CreateBinder(context);
            var result2 = factory.CreateBinder(context);

            // Assert
            Assert.NotSame(result1, result2);
        }
        private static ModelBindingContext GetBindingContext(Type modelType, Type binderType = null)
        {
            var metadataProvider = new TestModelMetadataProvider();
            metadataProvider.ForType(modelType).BindingDetails(bd => bd.BinderType = binderType);

            var operationBindingContext = new OperationBindingContext
            {
                ActionContext = new ActionContext()
                {
                    HttpContext = new DefaultHttpContext(),
                },
                MetadataProvider = metadataProvider,
                ValidatorProvider = Mock.Of<IModelValidatorProvider>(),
            };

            var bindingContext = new ModelBindingContext
            {
                ModelMetadata = metadataProvider.GetMetadataForType(modelType),
                ModelName = "someName",
                ValueProvider = Mock.Of<IValueProvider>(),
                ModelState = new ModelStateDictionary(),
                OperationBindingContext = operationBindingContext,
                BinderType = binderType
            };

            return bindingContext;
        }