public void BinderShouldBindValues() {
            var controllerContext = new ControllerContext();

            var binders = new ModelBinderDictionary {
                { typeof(Foo), new DefaultModelBinder() } 
            };

            var input = new FormCollection { 
                { "fooInstance[Bar1].Value", "bar1value" }, 
                { "fooInstance[Bar2].Value", "bar2value" } 
            };

            var foos = new[] {
                new Foo {Name = "Bar1", Value = "uno"},
                new Foo {Name = "Bar2", Value = "dos"},
                new Foo {Name = "Bar3", Value = "tres"},
            };

            var providers = new EmptyModelMetadataProvider();

            var bindingContext = new ModelBindingContext {
                ModelMetadata = providers.GetMetadataForType(() => foos, foos.GetType()),
                ModelName = "fooInstance", 
                ValueProvider = input.ToValueProvider() 
            };

            var binder = new KeyedListModelBinder<Foo>(binders, providers, foo => foo.Name);

            var result = (IList<Foo>)binder.BindModel(controllerContext, bindingContext);

            Assert.That(result.Count, Is.EqualTo(3));
            Assert.That(result[0].Value, Is.EqualTo("bar1value"));
            Assert.That(result[1].Value, Is.EqualTo("bar2value"));
        }
        public void OnMetadataCreated_SetsAdditionalValuesKey() {
            // Arrange
            ModelMetadata metadata = new EmptyModelMetadataProvider().GetMetadataForType(null, typeof(object));
            metadata.AdditionalValues["someKey"] = "oldValue";

            AdditionalMetadataAttribute attr = new AdditionalMetadataAttribute("someKey", "newValue");

            // Act
            ((IMetadataAware)attr).OnMetadataCreated(metadata);

            // Assert
            Assert.AreEqual("newValue", metadata.AdditionalValues["someKey"]);
        }
        public void BindModel() {
            // Arrange
            ControllerContext controllerContext = new ControllerContext();
            MyModel model = new MyModel();
            ModelMetadata modelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => model, typeof(MyModel));
            ComplexModelDto dto = new ComplexModelDto(modelMetadata, modelMetadata.Properties);

            Mock<IExtensibleModelBinder> mockStringBinder = new Mock<IExtensibleModelBinder>();
            mockStringBinder
                .Expect(b => b.BindModel(controllerContext, It.IsAny<ExtensibleModelBindingContext>()))
                .Returns(
                    delegate(ControllerContext cc, ExtensibleModelBindingContext mbc) {
                        Assert.AreEqual(typeof(string), mbc.ModelType);
                        Assert.AreEqual("theModel.StringProperty", mbc.ModelName);
                        mbc.ValidationNode = new ModelValidationNode(mbc.ModelMetadata, "theModel.StringProperty");
                        mbc.Model = "someStringValue";
                        return true;
                    });

            Mock<IExtensibleModelBinder> mockIntBinder = new Mock<IExtensibleModelBinder>();
            mockIntBinder
                .Expect(b => b.BindModel(controllerContext, It.IsAny<ExtensibleModelBindingContext>()))
                .Returns(
                    delegate(ControllerContext cc, ExtensibleModelBindingContext mbc) {
                        Assert.AreEqual(typeof(int), mbc.ModelType);
                        Assert.AreEqual("theModel.IntProperty", mbc.ModelName);
                        mbc.ValidationNode = new ModelValidationNode(mbc.ModelMetadata, "theModel.IntProperty");
                        mbc.Model = 42;
                        return true;
                    });

            Mock<IExtensibleModelBinder> mockDateTimeBinder = new Mock<IExtensibleModelBinder>();
            mockDateTimeBinder
                .Expect(b => b.BindModel(controllerContext, It.IsAny<ExtensibleModelBindingContext>()))
                .Returns(
                    delegate(ControllerContext cc, ExtensibleModelBindingContext mbc) {
                        Assert.AreEqual(typeof(DateTime), mbc.ModelType);
                        Assert.AreEqual("theModel.DateTimeProperty", mbc.ModelName);
                        return false;
                    });

            ModelBinderProviderCollection binders = new ModelBinderProviderCollection();
            binders.RegisterBinderForType(typeof(string), mockStringBinder.Object, true /* suppressPrefixCheck */);
            binders.RegisterBinderForType(typeof(int), mockIntBinder.Object, true /* suppressPrefixCheck */);
            binders.RegisterBinderForType(typeof(DateTime), mockDateTimeBinder.Object, true /* suppressPrefixCheck */);

            ExtensibleModelBindingContext parentBindingContext = new ExtensibleModelBindingContext() {
                ModelMetadata = new EmptyModelMetadataProvider().GetMetadataForType(() => dto, typeof(ComplexModelDto)),
                ModelName = "theModel",
                ModelBinderProviders = binders
            };

            ComplexModelDtoModelBinder binder = new ComplexModelDtoModelBinder();

            // Act
            bool retVal = binder.BindModel(controllerContext, parentBindingContext);

            // Assert
            Assert.IsTrue(retVal);
            Assert.AreEqual(dto, parentBindingContext.Model, "The return model should have been the original DTO.");

            ComplexModelDtoResult stringDtoResult = dto.Results[dto.PropertyMetadata.Where(m => m.ModelType == typeof(string)).First()];
            Assert.AreEqual("someStringValue", stringDtoResult.Model);
            Assert.AreEqual("theModel.StringProperty", stringDtoResult.ValidationNode.ModelStateKey);

            ComplexModelDtoResult intDtoResult = dto.Results[dto.PropertyMetadata.Where(m => m.ModelType == typeof(int)).First()];
            Assert.AreEqual(42, intDtoResult.Model);
            Assert.AreEqual("theModel.IntProperty", intDtoResult.ValidationNode.ModelStateKey);

            ComplexModelDtoResult dateTimeDtoResult = dto.Results[dto.PropertyMetadata.Where(m => m.ModelType == typeof(DateTime)).First()];
            Assert.IsNull(dateTimeDtoResult);
        }
 private static ModelValidationNode GetValidationNode()
 {
     EmptyModelMetadataProvider provider = new EmptyModelMetadataProvider();
     ModelMetadata metadata = provider.GetMetadataForType(null, typeof(object));
     return new ModelValidationNode(metadata, "someKey");
 }
 private static ModelMetadata GetModelMetadata() {
     EmptyModelMetadataProvider provider = new EmptyModelMetadataProvider();
     return provider.GetMetadataForType(null, typeof(object));
 }
        public void Validate_SkipsRemainingValidationIfModelStateIsInvalid() {
            // Because a property validator fails, the model validator shouldn't run

            // Arrange
            List<string> log = new List<string>();
            LoggingDataErrorInfoModel model = new LoggingDataErrorInfoModel(log);
            ModelMetadata modelMetadata = GetModelMetadata(model);

            ControllerContext controllerContext = new ControllerContext() {
                Controller = new EmptyController()
            };
            ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey");

            ModelMetadata childMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(() => model, model.GetType(), "InvalidStringProperty");
            node.ChildNodes.Add(new ModelValidationNode(childMetadata, "theKey.InvalidStringProperty"));

            node.Validating += delegate {
                log.Add("In OnValidating()");
            };
            node.Validated += delegate {
                log.Add("In OnValidated()");
            };

            // Act
            node.Validate(controllerContext);

            // Assert
            CollectionAssert.AreEqual(
                new string[] { "In OnValidating()", "In IDataErrorInfo.get_Item('InvalidStringProperty')", "In OnValidated()" },
                log);

            Assert.AreEqual("Sample error message", controllerContext.Controller.ViewData.ModelState["theKey.InvalidStringProperty"].Errors[0].ErrorMessage);
        }
        public void Validate_Ordering() {
            // Proper order of invocation:
            // 1. OnValidating()
            // 2. Child validators
            // 3. This validator
            // 4. OnValidated()

            // Arrange
            List<string> log = new List<string>();
            LoggingDataErrorInfoModel model = new LoggingDataErrorInfoModel(log);
            ModelMetadata modelMetadata = GetModelMetadata(model);

            ControllerContext controllerContext = new ControllerContext() {
                Controller = new EmptyController()
            };
            ModelValidationNode node = new ModelValidationNode(modelMetadata, "theKey");

            ModelMetadata childMetadata = new EmptyModelMetadataProvider().GetMetadataForProperty(() => model, model.GetType(), "ValidStringProperty");
            node.ChildNodes.Add(new ModelValidationNode(childMetadata, "theKey.ValidStringProperty"));

            node.Validating += delegate {
                log.Add("In OnValidating()");
            };
            node.Validated += delegate {
                log.Add("In OnValidated()");
            };

            // Act
            node.Validate(controllerContext);

            // Assert
            CollectionAssert.AreEqual(
                new string[] { "In OnValidating()", "In IDataErrorInfo.get_Item('ValidStringProperty')", "In IDataErrorInfo.get_Error()", "In OnValidated()" },
                log);
        }
         public ControllerData(Type type) {

            var metadataProvider = new EmptyModelMetadataProvider();
            
            this.Properties =
               (from p in type.GetProperties()
                let attr = p.GetCustomAttributes(typeof(FromRouteAttr), inherit: true)
                  .Cast<FromRouteAttr>()
                  .SingleOrDefault()
                where attr != null
                select new PropertyData(
                   property: p,
                   attribute: attr,
                   metadata: metadataProvider.GetMetadataForType(null, p.PropertyType)
                )).ToArray();
         }