// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Routing; using Moq; using Xunit; namespace Microsoft.AspNet.Mvc.Core.Test { public class ControllerActionArgumentBinderTests { [Fact] public async Task Parameters_WithMultipleFromBody_Throw() { // Arrange var actionDescriptor = new ControllerActionDescriptor { MethodInfo = typeof(TestController).GetMethod("ActionWithTwoBodyParam"), Parameters = new List { new ParameterDescriptor { Name = "bodyParam", ParameterType = typeof(Person), }, new ParameterDescriptor { Name = "bodyParam1", ParameterType = typeof(Person), } } }; var binder = new Mock(); var metadataProvider = new DataAnnotationsModelMetadataProvider(); var actionContext = new ActionContext(new RouteContext(Mock.Of()), actionDescriptor); actionContext.Controller = Mock.Of(); var bindingContext = new ActionBindingContext(actionContext, metadataProvider, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()); var actionBindingContextProvider = new Mock(); actionBindingContextProvider.Setup(p => p.GetActionBindingContextAsync(It.IsAny())) .Returns(Task.FromResult(bindingContext)); var invoker = new DefaultControllerActionArgumentBinder( actionBindingContextProvider.Object, Mock.Of()); // Act var ex = await Assert.ThrowsAsync( () => invoker.GetActionArgumentsAsync(actionContext)); // Assert Assert.Equal("More than one parameter is bound to the HTTP request's content.", ex.Message); } [Fact] public async Task GetActionArgumentsAsync_DoesNotAddActionArguments_IfBinderReturnsFalse() { // Arrange Func method = foo => 1; var actionDescriptor = new ControllerActionDescriptor { MethodInfo = method.Method, Parameters = new List { new ParameterDescriptor { Name = "foo", ParameterBindingInfo = new ParameterBindingInfo("foo", typeof(object)) } } }; var binder = new Mock(); binder.Setup(b => b.BindModelAsync(It.IsAny())) .Returns(Task.FromResult(result: false)); var actionContext = new ActionContext(new RouteContext(Mock.Of()), actionDescriptor); actionContext.Controller = Mock.Of(); var bindingContext = new ActionBindingContext(actionContext, Mock.Of(), binder.Object, Mock.Of(), Mock.Of(), Mock.Of()); var inputFormattersProvider = new Mock(); inputFormattersProvider.SetupGet(o => o.InputFormatters) .Returns(new List()); var actionBindingContextProvider = new Mock(); actionBindingContextProvider.Setup(p => p.GetActionBindingContextAsync(It.IsAny())) .Returns(Task.FromResult(bindingContext)); var invoker = new DefaultControllerActionArgumentBinder( actionBindingContextProvider.Object, Mock.Of()); // Act var result = await invoker.GetActionArgumentsAsync(actionContext); // Assert Assert.Empty(result); } [Fact] public async Task GetActionArgumentsAsync_AddsActionArguments_IfBinderReturnsTrue() { // Arrange Func method = foo => 1; var actionDescriptor = new ControllerActionDescriptor { MethodInfo = method.Method, Parameters = new List { new ParameterDescriptor { Name = "foo", ParameterType = typeof(string), } } }; var value = "Hello world"; var binder = new Mock(); var metadataProvider = new EmptyModelMetadataProvider(); binder.Setup(b => b.BindModelAsync(It.IsAny())) .Callback((ModelBindingContext context) => { context.ModelMetadata = metadataProvider.GetMetadataForType(modelAccessor: null, modelType: typeof(string)); context.Model = value; }) .Returns(Task.FromResult(result: true)); var actionContext = new ActionContext(new RouteContext(Mock.Of()), actionDescriptor); actionContext.Controller = Mock.Of(); var bindingContext = new ActionBindingContext(actionContext, metadataProvider, binder.Object, Mock.Of(), Mock.Of(), Mock.Of()); var actionBindingContextProvider = new Mock(); actionBindingContextProvider.Setup(p => p.GetActionBindingContextAsync(It.IsAny())) .Returns(Task.FromResult(bindingContext)); var invoker = new DefaultControllerActionArgumentBinder( actionBindingContextProvider.Object, Mock.Of()); // Act var result = await invoker.GetActionArgumentsAsync(actionContext); // Assert Assert.Equal(1, result.Count); Assert.Equal(value, result["foo"]); } private class TestController { public string UnmarkedProperty { get; set; } [NonValueBinderMarker] public string NonValueBinderMarkedProperty { get; set; } [ValueBinderMarker] public string ValueBinderMarkedProperty { get; set; } public Person ActionWithBodyParam([FromBody] Person bodyParam) { return bodyParam; } public Person ActionWithTwoBodyParam([FromBody] Person bodyParam, [FromBody] Person bodyParam1) { return bodyParam; } } private class NonValueBinderMarkerAttribute : Attribute, IBinderMarker { } private class ValueBinderMarkerAttribute : Attribute, IValueBinderMarker { } } }