aspnetcore/test/Microsoft.AspNet.Mvc.Core.Test/ParameterBinding/ControllerActionArgumentBin...

316 lines
12 KiB
C#

// 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.Reflection;
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
{
public class MySimpleModel
{
}
[Bind(Prefix = "TypePrefix")]
public class MySimpleModelWithTypeBasedBind
{
}
public void ParameterWithNoBindAttribute(MySimpleModelWithTypeBasedBind parameter)
{
}
public void ParameterHasFieldPrefix([Bind(Prefix = "simpleModelPrefix")] string parameter)
{
}
public void ParameterHasEmptyFieldPrefix([Bind(Prefix = "")] MySimpleModel parameter,
[Bind(Prefix = "")] MySimpleModelWithTypeBasedBind parameter1)
{
}
public void ParameterHasPrefixAndComplexType(
[Bind(Prefix = "simpleModelPrefix")] MySimpleModel parameter,
[Bind(Prefix = "simpleModelPrefix")] MySimpleModelWithTypeBasedBind parameter1)
{
}
public void ParameterHasEmptyBindAttribute([Bind] MySimpleModel parameter,
[Bind] MySimpleModelWithTypeBasedBind parameter1)
{
}
[Fact]
public void GetModelBindingContext_ReturnsOnlyIncludedProperties_UsingBindAttributeInclude()
{
// Arrange
var actionContext = new ActionContext(
new RouteContext(Mock.Of<HttpContext>()),
Mock.Of<ActionDescriptor>());
var metadataProvider = new DataAnnotationsModelMetadataProvider();
var modelMetadata = metadataProvider.GetMetadataForType(
modelAccessor: null, modelType: typeof(TypeWithIncludedPropertiesUsingBindAttribute));
var actionBindingContext = new ActionBindingContext();
// Act
var context = DefaultControllerActionArgumentBinder.GetModelBindingContext(
modelMetadata,
actionContext,
Mock.Of<OperationBindingContext>());
// Assert
Assert.True(context.PropertyFilter(context, "IncludedExplicitly1"));
Assert.True(context.PropertyFilter(context, "IncludedExplicitly2"));
}
[Fact]
public void GetModelBindingContext_UsesBindAttributeOnType_IfNoBindAttributeOnParameter_ForPrefix()
{
// Arrange
var type = typeof(ControllerActionArgumentBinderTests);
var methodInfo = type.GetMethod("ParameterWithNoBindAttribute");
var actionContext = new ActionContext(
new RouteContext(Mock.Of<HttpContext>()),
Mock.Of<ActionDescriptor>());
var metadataProvider = new DataAnnotationsModelMetadataProvider();
var modelMetadata = metadataProvider.GetMetadataForParameter(modelAccessor: null,
methodInfo: methodInfo,
parameterName: "parameter");
// Act
var context = DefaultControllerActionArgumentBinder.GetModelBindingContext(
modelMetadata,
actionContext,
Mock.Of<OperationBindingContext>());
// Assert
Assert.Equal("TypePrefix", context.ModelName);
}
[Theory]
[InlineData("ParameterHasFieldPrefix", false, "simpleModelPrefix")]
[InlineData("ParameterHasEmptyFieldPrefix", false, "")]
[InlineData("ParameterHasPrefixAndComplexType", false, "simpleModelPrefix")]
[InlineData("ParameterHasEmptyBindAttribute", true, "parameter")]
public void GetModelBindingContext_ModelBindingContextIsSetWithModelName_ForParameters(
string actionMethodName, bool expectedFallToEmptyPrefix, string expectedModelName)
{
// Arrange
var type = typeof(ControllerActionArgumentBinderTests);
var methodInfo = type.GetMethod(actionMethodName);
var actionContext = new ActionContext(
new RouteContext(Mock.Of<HttpContext>()),
Mock.Of<ActionDescriptor>());
var metadataProvider = new DataAnnotationsModelMetadataProvider();
var modelMetadata = metadataProvider.GetMetadataForParameter(modelAccessor: null,
methodInfo: methodInfo,
parameterName: "parameter");
// Act
var context = DefaultControllerActionArgumentBinder.GetModelBindingContext(
modelMetadata,
actionContext,
Mock.Of<OperationBindingContext>());
// Assert
Assert.Equal(expectedFallToEmptyPrefix, context.FallbackToEmptyPrefix);
Assert.Equal(expectedModelName, context.ModelName);
}
[Theory]
[InlineData("ParameterHasEmptyFieldPrefix", false, "")]
[InlineData("ParameterHasPrefixAndComplexType", false, "simpleModelPrefix")]
[InlineData("ParameterHasEmptyBindAttribute", true, "parameter1")]
public void GetModelBindingContext_ModelBindingContextIsNotSet_ForTypes(
string actionMethodName, bool expectedFallToEmptyPrefix, string expectedModelName)
{
// Arrange
var type = typeof(ControllerActionArgumentBinderTests);
var methodInfo = type.GetMethod(actionMethodName);
var actionContext = new ActionContext(
new RouteContext(Mock.Of<HttpContext>()),
Mock.Of<ActionDescriptor>());
var metadataProvider = new DataAnnotationsModelMetadataProvider();
var modelMetadata = metadataProvider.GetMetadataForParameter(modelAccessor: null,
methodInfo: methodInfo,
parameterName: "parameter1");
// Act
var context = DefaultControllerActionArgumentBinder.GetModelBindingContext(
modelMetadata,
actionContext,
Mock.Of<OperationBindingContext>());
// Assert
Assert.Equal(expectedFallToEmptyPrefix, context.FallbackToEmptyPrefix);
Assert.Equal(expectedModelName, context.ModelName);
}
[Fact]
public async Task GetActionArgumentsAsync_DoesNotAddActionArguments_IfBinderReturnsFalse()
{
// Arrange
Func<object, int> method = foo => 1;
var actionDescriptor = new ControllerActionDescriptor
{
MethodInfo = method.Method,
Parameters = new List<ParameterDescriptor>
{
new ParameterDescriptor
{
Name = "foo",
ParameterType = typeof(object),
}
}
};
var binder = new Mock<IModelBinder>();
binder
.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.Returns(Task.FromResult(result: false));
var actionContext = new ActionContext(
new RouteContext(Mock.Of<HttpContext>()),
actionDescriptor)
{
Controller = Mock.Of<object>(),
};
var actionBindingContext = new ActionBindingContext()
{
ModelBinder = binder.Object,
};
var inputFormattersProvider = new Mock<IInputFormattersProvider>();
inputFormattersProvider
.SetupGet(o => o.InputFormatters)
.Returns(new List<IInputFormatter>());
var invoker = new DefaultControllerActionArgumentBinder(new DataAnnotationsModelMetadataProvider());
// Act
var result = await invoker.GetActionArgumentsAsync(actionContext, actionBindingContext);
// Assert
Assert.Empty(result);
}
[Fact]
public async Task GetActionArgumentsAsync_AddsActionArguments_IfBinderReturnsTrue()
{
// Arrange
Func<object, int> method = foo => 1;
var actionDescriptor = new ControllerActionDescriptor
{
MethodInfo = method.Method,
Parameters = new List<ParameterDescriptor>
{
new ParameterDescriptor
{
Name = "foo",
ParameterType = typeof(string),
}
},
};
var value = "Hello world";
var metadataProvider = new EmptyModelMetadataProvider();
var binder = new Mock<IModelBinder>();
binder
.Setup(b => b.BindModelAsync(It.IsAny<ModelBindingContext>()))
.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<HttpContext>()),
actionDescriptor)
{
Controller = Mock.Of<object>(),
};
var actionBindingContext = new ActionBindingContext()
{
ModelBinder = binder.Object,
};
var invoker = new DefaultControllerActionArgumentBinder(metadataProvider);
// Act
var result = await invoker.GetActionArgumentsAsync(actionContext, actionBindingContext);
// Assert
Assert.Equal(1, result.Count);
Assert.Equal(value, result["foo"]);
}
private class TestController
{
public string UnmarkedProperty { get; set; }
[NonValueProviderBinderMetadata]
public string NonValueBinderMarkedProperty { get; set; }
[ValueProviderMetadata]
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 Person
{
public string Name { get; set; }
}
private class NonValueProviderBinderMetadataAttribute : Attribute, IBinderMetadata
{
}
private class ValueProviderMetadataAttribute : Attribute, IValueProviderMetadata
{
}
[Bind(new string[] { nameof(IncludedExplicitly1), nameof(IncludedExplicitly2) })]
private class TypeWithIncludedPropertiesUsingBindAttribute
{
public int ExcludedByDefault1 { get; set; }
public int ExcludedByDefault2 { get; set; }
public int IncludedExplicitly1 { get; set; }
public int IncludedExplicitly2 { get; set; }
}
}
}