Esempio n. 1
0
        public async Task BindActionArgumentsAsync_SupportsRequestPredicate_ForPropertiesAndParameters_Bound()
        {
            // Arrange
            var actionDescriptor = GetActionDescriptor();

            actionDescriptor.Parameters.Add(new ParameterDescriptor
            {
                Name        = "test-parameter",
                BindingInfo = new BindingInfo()
                {
                    BindingSource = BindingSource.Custom,

                    // Simulates [BindProperty] on a parameter
                    RequestPredicate = ((IRequestPredicateProvider) new BindPropertyAttribute()).RequestPredicate,
                },
                ParameterType = typeof(string)
            });

            actionDescriptor.BoundProperties.Add(new ParameterDescriptor
            {
                Name        = nameof(TestController.NullableProperty),
                BindingInfo = new BindingInfo()
                {
                    BindingSource = BindingSource.Custom,

                    // Simulates [BindProperty] on a property
                    RequestPredicate = ((IRequestPredicateProvider) new BindPropertyAttribute()).RequestPredicate,
                },
                ParameterType = typeof(string)
            });

            var controllerContext = GetControllerContext(actionDescriptor);

            controllerContext.HttpContext.Request.Method = "POST";

            var controller = new TestController();
            var arguments  = new Dictionary <string, object>(StringComparer.Ordinal);

            var binder          = new StubModelBinder(ModelBindingResult.Success(model: null));
            var factory         = GetModelBinderFactory(binder);
            var parameterBinder = GetParameterBinder(factory);

            // Some non default value.
            controller.NullableProperty = -1;

            // Act
            var binderDelegate = ControllerBinderDelegateProvider.CreateBinderDelegate(
                parameterBinder,
                factory,
                TestModelMetadataProvider.CreateDefaultProvider(),
                actionDescriptor);

            await binderDelegate(controllerContext, controller, arguments);

            // Assert
            Assert.Null(controller.NullableProperty);
            Assert.Contains("test-parameter", arguments.Keys);
            Assert.Null(arguments["test-parameter"]);
        }
Esempio n. 2
0
        public async Task BindActionArgumentsAsync_DoesNotCallValidator_IfModelBinderFails()
        {
            // Arrange
            Func <object, int> method = foo => 1;
            var actionDescriptor      = GetActionDescriptor();

            actionDescriptor.Parameters.Add(
                new ParameterDescriptor
            {
                Name          = "foo",
                ParameterType = typeof(object),
                BindingInfo   = new BindingInfo(),
            });

            var controllerContext = GetControllerContext(actionDescriptor);
            var arguments         = new Dictionary <string, object>(StringComparer.Ordinal);

            var binder = new Mock <IModelBinder>();

            binder
            .Setup(b => b.BindModelAsync(It.IsAny <DefaultModelBindingContext>()))
            .Returns(Task.CompletedTask);

            var mockValidator = new Mock <IObjectModelValidator>(MockBehavior.Strict);

            mockValidator
            .Setup(o => o.Validate(
                       It.IsAny <ActionContext>(),
                       It.IsAny <ValidationStateDictionary>(),
                       It.IsAny <string>(),
                       It.IsAny <object>()));

            var factory         = GetModelBinderFactory(binder.Object);
            var controller      = new TestController();
            var parameterBinder = GetParameterBinder(factory, mockValidator.Object);

            // Act
            var binderDelegate = ControllerBinderDelegateProvider.CreateBinderDelegate(
                parameterBinder,
                factory,
                TestModelMetadataProvider.CreateDefaultProvider(),
                actionDescriptor);

            await binderDelegate(controllerContext, controller, arguments);

            // Assert
            mockValidator
            .Verify(o => o.Validate(
                        It.IsAny <ActionContext>(),
                        It.IsAny <ValidationStateDictionary>(),
                        It.IsAny <string>(),
                        It.IsAny <object>()),
                    Times.Never());
        }
Esempio n. 3
0
        public async Task BindActionArgumentsAsync_CallsValidator_IfModelBinderSucceeds()
        {
            // Arrange
            var actionDescriptor = GetActionDescriptor();

            actionDescriptor.Parameters.Add(
                new ParameterDescriptor
            {
                Name          = "foo",
                ParameterType = typeof(object),
            });

            var controllerContext = GetControllerContext(actionDescriptor);

            var factory = GetModelBinderFactory("Hello");

            var mockValidator = new Mock <IObjectModelValidator>(MockBehavior.Strict);

            mockValidator
            .Setup(o => o.Validate(
                       It.IsAny <ActionContext>(),
                       It.IsAny <ValidationStateDictionary>(),
                       It.IsAny <string>(),
                       It.IsAny <object>()));

            var parameterBinder = GetParameterBinder(factory, mockValidator.Object);
            var controller      = new TestController();
            var arguments       = new Dictionary <string, object>(StringComparer.Ordinal);

            // Act
            var binderDelegate = ControllerBinderDelegateProvider.CreateBinderDelegate(
                parameterBinder,
                factory,
                TestModelMetadataProvider.CreateDefaultProvider(),
                actionDescriptor);

            await binderDelegate(controllerContext, controller, arguments);

            // Assert
            mockValidator
            .Verify(o => o.Validate(
                        It.IsAny <ActionContext>(),
                        It.IsAny <ValidationStateDictionary>(),
                        It.IsAny <string>(),
                        It.IsAny <object>()),
                    Times.Once());
        }
Esempio n. 4
0
        public async Task BindActionArgumentsAsync_AddsActionArguments_IfBinderReturnsNotNull()
        {
            // Arrange
            Func <object, int> method = foo => 1;
            var actionDescriptor      = GetActionDescriptor();

            actionDescriptor.Parameters.Add(
                new ParameterDescriptor
            {
                Name          = "foo",
                ParameterType = typeof(string),
                BindingInfo   = new BindingInfo(),
            });

            var value            = "Hello world";
            var metadataProvider = new EmptyModelMetadataProvider();

            var binder = new Mock <IModelBinder>();

            binder
            .Setup(b => b.BindModelAsync(It.IsAny <DefaultModelBindingContext>()))
            .Callback((ModelBindingContext context) =>
            {
                context.ModelMetadata = metadataProvider.GetMetadataForType(typeof(string));
                context.Result        = ModelBindingResult.Success(value);
            })
            .Returns(Task.CompletedTask);
            var factory         = GetModelBinderFactory(binder.Object);
            var parameterBinder = GetParameterBinder(factory);

            var controllerContext = GetControllerContext(actionDescriptor);
            var controller        = new TestController();
            var arguments         = new Dictionary <string, object>(StringComparer.Ordinal);

            // Act
            var binderDelegate = ControllerBinderDelegateProvider.CreateBinderDelegate(
                parameterBinder,
                factory,
                TestModelMetadataProvider.CreateDefaultProvider(),
                actionDescriptor);

            await binderDelegate(controllerContext, controller, arguments);

            // Assert
            Assert.Equal(1, arguments.Count);
            Assert.Equal(value, arguments["foo"]);
        }
        public (ControllerActionInvokerCacheEntry cacheEntry, IFilterMetadata[] filters) GetCachedResult(ControllerContext controllerContext)
        {
            var cache            = CurrentCache;
            var actionDescriptor = controllerContext.ActionDescriptor;

            IFilterMetadata[] filters;
            if (!cache.Entries.TryGetValue(actionDescriptor, out var cacheEntry))
            {
                var filterFactoryResult = FilterFactory.GetAllFilters(_filterProviders, controllerContext);
                filters = filterFactoryResult.Filters;

                var parameterDefaultValues = ParameterDefaultValues
                                             .GetParameterDefaultValues(actionDescriptor.MethodInfo);

                var objectMethodExecutor = ObjectMethodExecutor.Create(
                    actionDescriptor.MethodInfo,
                    actionDescriptor.ControllerTypeInfo,
                    parameterDefaultValues);

                var controllerFactory     = _controllerFactoryProvider.CreateControllerFactory(actionDescriptor);
                var controllerReleaser    = _controllerFactoryProvider.CreateControllerReleaser(actionDescriptor);
                var propertyBinderFactory = ControllerBinderDelegateProvider.CreateBinderDelegate(
                    _parameterBinder,
                    _modelBinderFactory,
                    _modelMetadataProvider,
                    actionDescriptor,
                    _mvcOptions);

                var actionMethodExecutor = ActionMethodExecutor.GetExecutor(objectMethodExecutor);

                cacheEntry = new ControllerActionInvokerCacheEntry(
                    filterFactoryResult.CacheableFilters,
                    controllerFactory,
                    controllerReleaser,
                    propertyBinderFactory,
                    objectMethodExecutor,
                    actionMethodExecutor);
                cacheEntry = cache.Entries.GetOrAdd(actionDescriptor, cacheEntry);
            }
            else
            {
                // Filter instances from statically defined filter descriptors + from filter providers
                filters = FilterFactory.CreateUncachedFilters(_filterProviders, controllerContext, cacheEntry.CachedFilters);
            }

            return(cacheEntry, filters);
        }
Esempio n. 6
0
        public async Task BindActionArgumentsAsync_SetsNullValues_ForNullableProperties()
        {
            // Arrange
            var actionDescriptor = GetActionDescriptor();

            actionDescriptor.BoundProperties.Add(
                new ParameterDescriptor
            {
                Name        = "NullableProperty",
                BindingInfo = new BindingInfo()
                {
                    BindingSource = BindingSource.Custom
                },
                ParameterType = typeof(int?)
            });

            var controllerContext = GetControllerContext(actionDescriptor);
            var controller        = new TestController();
            var arguments         = new Dictionary <string, object>(StringComparer.Ordinal);

            var binder          = new StubModelBinder(ModelBindingResult.Success(model: null));
            var factory         = GetModelBinderFactory(binder);
            var parameterBinder = GetParameterBinder(factory);


            // Some non default value.
            controller.NullableProperty = -1;

            // Act
            var binderDelegate = ControllerBinderDelegateProvider.CreateBinderDelegate(
                parameterBinder,
                factory,
                TestModelMetadataProvider.CreateDefaultProvider(),
                actionDescriptor);

            await binderDelegate(controllerContext, controller, arguments);

            // Assert
            Assert.Null(controller.NullableProperty);
        }
Esempio n. 7
0
        public async Task BindActionArgumentsAsync_SkipsReadOnlyControllerProperties(
            string propertyName,
            Type propertyType,
            Func <object, object> propertyAccessor,
            object inputValue,
            object expectedValue)
        {
            // Arrange
            var actionDescriptor = GetActionDescriptor();

            actionDescriptor.BoundProperties.Add(
                new ParameterDescriptor
            {
                Name          = propertyName,
                BindingInfo   = new BindingInfo(),
                ParameterType = propertyType,
            });

            var controllerContext = GetControllerContext(actionDescriptor);
            var controller        = new TestController();
            var arguments         = new Dictionary <string, object>(StringComparer.Ordinal);

            var factory         = GetModelBinderFactory(inputValue);
            var parameterBinder = GetParameterBinder(factory);

            // Act
            var binderDelegate = ControllerBinderDelegateProvider.CreateBinderDelegate(
                parameterBinder,
                factory,
                TestModelMetadataProvider.CreateDefaultProvider(),
                actionDescriptor);

            await binderDelegate(controllerContext, controller, arguments);

            // Assert
            Assert.Equal(expectedValue, propertyAccessor(controller));
            Assert.Null(controller.StringProperty);
            Assert.Null(controller.UntouchedProperty);
        }
Esempio n. 8
0
        public async Task BindActionArgumentsAsync_DoesNotAddActionArguments_IfBinderDoesNotSetModel()
        {
            // Arrange
            var actionDescriptor = GetActionDescriptor();

            actionDescriptor.Parameters.Add(
                new ParameterDescriptor
            {
                Name          = "foo",
                ParameterType = typeof(object),
                BindingInfo   = new BindingInfo(),
            });

            var binder = new Mock <IModelBinder>();

            binder
            .Setup(b => b.BindModelAsync(It.IsAny <DefaultModelBindingContext>()))
            .Returns(Task.CompletedTask);
            var factory         = GetModelBinderFactory(binder.Object);
            var parameterBinder = GetParameterBinder(factory);

            var controllerContext = GetControllerContext(actionDescriptor);
            var controller        = new TestController();
            var arguments         = new Dictionary <string, object>(StringComparer.Ordinal);

            // Act
            var binderDelegate = ControllerBinderDelegateProvider.CreateBinderDelegate(
                parameterBinder,
                factory,
                TestModelMetadataProvider.CreateDefaultProvider(),
                actionDescriptor);

            await binderDelegate(controllerContext, controller, arguments);

            // Assert
            Assert.Empty(arguments);
        }
Esempio n. 9
0
        public async Task BindActionArgumentsAsync_AddsToCollectionControllerProperties()
        {
            // Arrange
            var actionDescriptor = GetActionDescriptor();

            actionDescriptor.BoundProperties.Add(
                new ParameterDescriptor
            {
                Name          = nameof(TestController.CollectionProperty),
                BindingInfo   = new BindingInfo(),
                ParameterType = typeof(ICollection <string>),
            });

            var controllerContext = GetControllerContext(actionDescriptor);
            var controller        = new TestController();
            var arguments         = new Dictionary <string, object>(StringComparer.Ordinal);

            var expected = new List <string> {
                "Hello", "World", "!!"
            };
            var factory         = GetModelBinderFactory(expected);
            var parameterBinder = GetParameterBinder(factory);

            // Act
            var binderDelegate = ControllerBinderDelegateProvider.CreateBinderDelegate(
                parameterBinder,
                factory,
                TestModelMetadataProvider.CreateDefaultProvider(),
                actionDescriptor);

            await binderDelegate(controllerContext, controller, arguments);

            // Assert
            Assert.Equal(expected, controller.CollectionProperty);
            Assert.Null(controller.StringProperty);
            Assert.Null(controller.UntouchedProperty);
        }
Esempio n. 10
0
        public async Task MultipleActionParameter_ValidModelState(List <ParameterDescriptor> parameters)
        {
            // Since validation attribute is only present on the FromBody model's property(TransferInfo's AccountId),
            // validation should not trigger for the parameter which is bound from Uri.

            // Arrange
            var actionDescriptor = new ControllerActionDescriptor()
            {
                BoundProperties = new List <ParameterDescriptor>(),
                Parameters      = parameters
            };
            var modelMetadataProvider = new EmptyModelMetadataProvider();
            var modelBinderProvider   = new BodyModelBinderProvider(new[] { Mock.Of <IInputFormatter>() }, Mock.Of <IHttpRequestStreamReaderFactory>());
            var factory         = TestModelBinderFactory.CreateDefault(modelBinderProvider);
            var parameterBinder = new Mock <ParameterBinder>(
                new EmptyModelMetadataProvider(),
                factory,
                CreateMockValidator());

            parameterBinder.Setup(p => p.BindModelAsync(
                                      It.IsAny <ActionContext>(),
                                      It.IsAny <IModelBinder>(),
                                      It.IsAny <IValueProvider>(),
                                      It.IsAny <ParameterDescriptor>(),
                                      It.IsAny <ModelMetadata>(),
                                      null))
            .Returns((ActionContext context, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor descriptor, ModelMetadata metadata, object v) =>
            {
                ModelBindingResult result;
                if (descriptor.Name == "accountId")
                {
                    result = ModelBindingResult.Success(10);
                }
                else if (descriptor.Name == "transferInfo")
                {
                    result = ModelBindingResult.Success(new TransferInfo
                    {
                        AccountId = 40,
                        Amount    = 250.0
                    });
                }
                else
                {
                    result = ModelBindingResult.Failed();
                }

                return(Task.FromResult(result));
            });

            var controllerContext = new ControllerContext
            {
                ActionDescriptor = actionDescriptor,
            };

            var arguments  = new Dictionary <string, object>(StringComparer.Ordinal);
            var modelState = controllerContext.ModelState;

            // Act
            var binderDelegate = ControllerBinderDelegateProvider.CreateBinderDelegate(
                parameterBinder.Object,
                factory,
                TestModelMetadataProvider.CreateDefaultProvider(),
                actionDescriptor);

            await binderDelegate(controllerContext, new TestController(), arguments);

            // Assert
            Assert.True(modelState.IsValid);
            Assert.True(arguments.TryGetValue("accountId", out var value));
            var accountId = Assert.IsType <int>(value);

            Assert.Equal(10, accountId);
            Assert.True(arguments.TryGetValue("transferInfo", out value));
            var transferInfo = Assert.IsType <TransferInfo>(value);

            Assert.NotNull(transferInfo);
            Assert.Equal(40, transferInfo.AccountId);
            Assert.Equal(250.0, transferInfo.Amount);
        }
Esempio n. 11
0
        public async Task BindActionArgumentsAsync_SetsMultipleControllerProperties()
        {
            // Arrange
            var boundPropertyTypes = new Dictionary <string, Type>
            {
                { nameof(TestController.ArrayProperty), typeof(string[]) },                // Skipped
                { nameof(TestController.CollectionProperty), typeof(List <string>) },
                { nameof(TestController.NonCollectionProperty), typeof(Person) },          // Skipped
                { nameof(TestController.NullCollectionProperty), typeof(List <string>) },  // Skipped
                { nameof(TestController.StringProperty), typeof(string) },
            };
            var inputPropertyValues = new Dictionary <string, object>
            {
                { nameof(TestController.ArrayProperty), new string[] { "hello", "world" } },
                { nameof(TestController.CollectionProperty), new List <string> {
                      "hello", "world"
                  } },
                { nameof(TestController.NonCollectionProperty), new Person {
                      Name = "Fred"
                  } },
                { nameof(TestController.NullCollectionProperty), new List <string> {
                      "hello", "world"
                  } },
                { nameof(TestController.StringProperty), "Hello" },
            };
            var expectedPropertyValues = new Dictionary <string, object>
            {
                { nameof(TestController.ArrayProperty), new string[] { "goodbye" } },
                { nameof(TestController.CollectionProperty), new List <string> {
                      "hello", "world"
                  } },
                { nameof(TestController.NonCollectionProperty), new Person {
                      Name = "Ginger"
                  } },
                { nameof(TestController.NullCollectionProperty), null },
                { nameof(TestController.StringProperty), "Hello" },
            };

            var actionDescriptor = GetActionDescriptor();

            foreach (var keyValuePair in boundPropertyTypes)
            {
                actionDescriptor.BoundProperties.Add(
                    new ParameterDescriptor
                {
                    Name          = keyValuePair.Key,
                    BindingInfo   = new BindingInfo(),
                    ParameterType = keyValuePair.Value,
                });
            }

            var controllerContext = GetControllerContext(actionDescriptor);
            var controller        = new TestController();
            var arguments         = new Dictionary <string, object>(StringComparer.Ordinal);

            var binder = new StubModelBinder(bindingContext =>
            {
                // BindingContext.ModelName will be string.Empty here. This is a 'fallback to empty prefix'
                // because the value providers have no data.
                object model;
                if (inputPropertyValues.TryGetValue(bindingContext.FieldName, out model))
                {
                    bindingContext.Result = ModelBindingResult.Success(model);
                }
                else
                {
                    bindingContext.Result = ModelBindingResult.Failed();
                }
            });

            var factory = GetModelBinderFactory(binder);

            controllerContext.ValueProviderFactories.Add(new SimpleValueProviderFactory());

            var parameterBinder = GetParameterBinder(factory);

            // Act
            var binderDelegate = ControllerBinderDelegateProvider.CreateBinderDelegate(
                parameterBinder,
                factory,
                TestModelMetadataProvider.CreateDefaultProvider(),
                actionDescriptor);

            await binderDelegate(controllerContext, controller, arguments);

            // Assert
            Assert.Equal(new string[] { "goodbye" }, controller.ArrayProperty);                 // Skipped
            Assert.Equal(new List <string> {
                "hello", "world"
            }, controller.CollectionProperty);
            Assert.Equal(new Person {
                Name = "Ginger"
            }, controller.NonCollectionProperty);                                               // Skipped
            Assert.Null(controller.NullCollectionProperty);                                     // Skipped
            Assert.Null(controller.UntouchedProperty);                                          // Not bound
            Assert.Equal("Hello", controller.StringProperty);
        }