/test/System.Web.Http.Test/ModelBinding/DefaultActionValueBinderTest.cs
C# | 490 lines | 348 code | 122 blank | 20 comment | 4 complexity | e351bd82de555c70aba865b91a0e2489 MD5 | raw file
- using System.ComponentModel;
- using System.Linq;
- using System.Net.Http;
- using System.Reflection;
- using System.Threading;
- using System.Web.Http.Controllers;
- using System.Web.Http.ValueProviders;
- using Xunit;
- using Assert = Microsoft.TestCommon.AssertEx;
- namespace System.Web.Http.ModelBinding
- {
- // These tests primarily focus on getting the right binding contract. They don't actually execute the contract.
- public class DefaultActionValueBinderTest
- {
- [Fact]
- public void BindValuesAsync_Throws_Null_ActionDescriptor()
- {
- // Arrange
- HttpActionDescriptor actionDescriptor = new ReflectedHttpActionDescriptor { MethodInfo = (MethodInfo)MethodInfo.GetCurrentMethod() };
-
- // Act and Assert
- Assert.ThrowsArgumentNull(
- () => new DefaultActionValueBinder().GetBinding(null),
- "actionDescriptor");
- }
- private void Action_Int(int id) { }
- [Fact]
- public void Check_Int_Is_ModelBound()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_Int"));
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsModelBound(binding, 0);
- }
- private void Action_Int_FromUri([FromUri] int id) { }
- [Fact]
- public void Check_Explicit_Int_Is_ModelBound()
- {
- // Even though int is implicitly model bound, still ok to specify it explicitly
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_Int_FromUri"));
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsModelBound(binding, 0);
- }
- // All types in this signature are model bound
- private void Action_SimpleTypes(char ch, Byte b, Int16 i16, UInt16 u16, Int32 i32, UInt32 u32, Int64 i64, UInt64 u64, string s, DateTime d, Decimal dec, Guid g, DateTimeOffset dateTimeOffset, TimeSpan timespan) { }
- [Fact]
- public void Check_SimpleTypes_Are_ModelBound()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_SimpleTypes"));
- for(int i = 0; i < binding.ParameterBindings.Length; i++)
- {
- AssertIsModelBound(binding, 0);
- }
- }
- private void Action_ComplexTypeWithStringConverter(ComplexTypeWithStringConverter x) { }
- [Fact]
- public void Check_String_TypeConverter_Is_ModelBound()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_ComplexTypeWithStringConverter"));
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsModelBound(binding, 0);
- }
- private void Action_ComplexTypeWithStringConverter_Body_Override([FromBody] ComplexTypeWithStringConverter x) { }
- [Fact]
- public void Check_String_TypeConverter_With_Body_Override()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_ComplexTypeWithStringConverter_Body_Override"));
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsBody(binding, 0);
- }
- private void Action_NullableInt(Nullable<int> id) { }
- [Fact]
- public void Check_NullableInt_Is_ModelBound()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_NullableInt"));
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsModelBound(binding, 0);
- }
- private void Action_Nullable_ValueType(Nullable<ComplexValueType> id) { }
- [Fact]
- public void Check_Nullable_ValueType_Is_FromBody()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
-
- var binding = binder.GetBinding(GetAction("Action_Nullable_ValueType"));
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsBody(binding, 0);
- }
- private void Action_IntArray(int[] arrayFrombody) { }
- [Fact]
- public void Check_IntArray_Is_FromBody()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_IntArray"));
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsBody(binding, 0);
- }
- private void Action_SimpleType_Body([FromBody] int i) { }
- [Fact]
- public void Check_SimpleType_Body()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_SimpleType_Body"));
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsBody(binding, 0);
- }
- private void Action_Empty() { }
- [Fact]
- public void Check_Empty_Action()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_Empty"));
- Assert.NotNull(binding.ParameterBindings);
- Assert.Equal(0, binding.ParameterBindings.Length);
- }
- private void Action_String_String(string s1, string s2) { }
- [Fact]
- public void Check_String_String_IsModelBound()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_String_String"));
- Assert.Equal(2, binding.ParameterBindings.Length);
- AssertIsModelBound(binding, 0);
- AssertIsModelBound(binding, 1);
- }
- private void Action_Complex_Type(ComplexType complex) { }
- [Fact]
- public void Check_Complex_Type_FromBody()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_Complex_Type"));
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsBody(binding, 0);
- }
- private void Action_Complex_ValueType(ComplexValueType complex) { }
- [Fact]
- public void Check_Complex_ValueType_FromBody()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_Complex_ValueType"));
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsBody(binding, 0);
- }
- private void Action_Default_Custom_Model_Binder([ModelBinder] ComplexType complex) { }
- [Fact]
- public void Check_Customer_Binder()
- {
- // Mere presence of a ModelBinder attribute means the type is model bound.
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_Default_Custom_Model_Binder"));
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsModelBound(binding, 0);
- }
- private void Action_Complex_Type_Uri([FromUri] ComplexType complex) { }
- [Fact]
- public void Check_Complex_Type_FromUri()
- {
- // [FromUri] is just a specific instance of ModelBinder attribute
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_Complex_Type_Uri"));
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsModelBound(binding, 0);
- }
- private void Action_Two_Complex_Types(ComplexType complexBody1, ComplexType complexBody2) { }
- [Fact]
- public void Check_Two_Complex_Types_FromBody()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- // It's illegal to have multiple parameters from the body.
- // But we should still be able to get a binding for it. We just can't execute it.
- var binding = binder.GetBinding(GetAction("Action_Two_Complex_Types"));
-
- Assert.Equal(2, binding.ParameterBindings.Length);
- AssertIsError(binding, 0);
- AssertIsError(binding, 1);
- }
- private void Action_Complex_Type_UriAndBody([FromUri] ComplexType complexUri, ComplexType complexBody) { }
- [Fact]
- public void Check_Complex_Type_FromBody_And_FromUri()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_Complex_Type_UriAndBody"));
- Assert.Equal(2, binding.ParameterBindings.Length);
- AssertIsModelBound(binding, 0);
- AssertIsBody(binding, 1);
- }
- private void Action_CancellationToken(CancellationToken ct) { }
- [Fact]
- public void Check_Cancellation_Token()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_CancellationToken"));
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsCancellationToken(binding, 0);
- }
- private void Action_CustomModelBinder_On_Parameter_WithProvider([ModelBinder(typeof(CustomModelBinderProvider))] ComplexType complex) { }
- [Fact]
- public void Check_CustomModelBinder_On_Parameter()
- {
- HttpConfiguration config = new HttpConfiguration();
- config.ServiceResolver.SetServices(typeof(ValueProviderFactory), new ValueProviderFactory[] {
- new CustomValueProviderFactory(),
- });
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_CustomModelBinder_On_Parameter_WithProvider", config));
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsModelBound(binding, 0);
- ModelBinderParameterBinding p = (ModelBinderParameterBinding) binding.ParameterBindings[0];
- Assert.IsType<CustomModelBinderProvider>(p.ModelBinderProvider);
- // Since the ModelBinderAttribute didn't specify the valueproviders, we should pull those from config.
- Assert.Equal(1, p.ValueProviderFactories.Count());
- Assert.IsType<CustomValueProviderFactory>(p.ValueProviderFactories.First());
- }
- // Model binder attribute is on the type's declaration.
- private void Action_ComplexParameter_With_ModelBinder(ComplexTypeWithModelBinder complex) { }
- [Fact]
- public void Check_Parameter_With_ModelBinder_Attribute_On_Type()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_ComplexParameter_With_ModelBinder"));
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsModelBound(binding, 0);
- }
- private void Action_Conflicting_Attributes([FromBody][FromUri] int i) { }
- [Fact]
- public void Error_Conflicting_Attributes()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_Conflicting_Attributes"));
- // Have 2 attributes that conflict with each other. Still get the contract, but it has an error in it.
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsError(binding, 0);
- }
- private void Action_HttpContent_Parameter(HttpContent c) { }
- [Fact]
- public void Check_HttpContent()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_HttpContent_Parameter"));
-
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsError(binding, 0);
- }
- private void Action_Derived_HttpContent_Parameter(StreamContent c) { }
- [Fact]
- public void Check_Derived_HttpContent()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_Derived_HttpContent_Parameter"));
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsError(binding, 0);
- }
- private void Action_Request_Parameter(HttpRequestMessage request) { }
- [Fact]
- public void Check_Request_Parameter()
- {
- DefaultActionValueBinder binder = new DefaultActionValueBinder();
- var binding = binder.GetBinding(GetAction("Action_Request_Parameter"));
- Assert.Equal(1, binding.ParameterBindings.Length);
- AssertIsCustomBinder<HttpRequestParameterBinding>(binding, 0);
- }
-
- // Assert that the binding contract says the given parameter comes from the body
- private void AssertIsBody(HttpActionBinding binding, int paramIdx)
- {
- HttpParameterBinding p = binding.ParameterBindings[paramIdx];
- Assert.NotNull(p);
- Assert.True(p.IsValid);
- Assert.True(p.WillReadBody);
- }
- // Assert that the binding contract says the given parameter is not from the body (will be handled by model binding)
- private void AssertIsModelBound(HttpActionBinding binding, int paramIdx)
- {
- HttpParameterBinding p = binding.ParameterBindings[paramIdx];
- Assert.NotNull(p);
- Assert.IsType<ModelBinderParameterBinding>(p);
- Assert.True(p.IsValid);
- Assert.False(p.WillReadBody);
- }
- // Assert that the binding contract says the given parameter will be bound to the cancellation token.
- private void AssertIsCancellationToken(HttpActionBinding binding, int paramIdx)
- {
- AssertIsCustomBinder<CancellationTokenParameterBinding>(binding, paramIdx);
- }
- private void AssertIsError(HttpActionBinding binding, int paramIdx)
- {
- HttpParameterBinding p = binding.ParameterBindings[paramIdx];
- Assert.NotNull(p);
- Assert.False(p.IsValid);
- Assert.False(p.WillReadBody);
- }
- private void AssertIsCustomBinder<T>(HttpActionBinding binding, int paramIdx)
- {
- HttpParameterBinding p = binding.ParameterBindings[paramIdx];
- Assert.NotNull(p);
- Assert.IsType<T>(p);
- Assert.True(p.IsValid);
- Assert.False(p.WillReadBody);
- }
- // Helper to get an ActionDescriptor for a method name.
- private HttpActionDescriptor GetAction(string name)
- {
- return GetAction(name, new HttpConfiguration());
- }
- private HttpActionDescriptor GetAction(string name, HttpConfiguration config)
- {
- MethodInfo method = this.GetType().GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
- Assert.NotNull(method);
- return new ReflectedHttpActionDescriptor { MethodInfo = method, Configuration = config };
- }
- // Complex type to use with tests
- class ComplexType
- {
- }
- struct ComplexValueType
- {
- }
- // Complex type to use with tests
- [ModelBinder]
- class ComplexTypeWithModelBinder
- {
- }
- // Add Type converter for string, which causes the type to be viewed as a Simple type.
- [TypeConverter(typeof(MyTypeConverter))]
- public class ComplexTypeWithStringConverter
- {
- public string Data { get; set; }
- public ComplexTypeWithStringConverter(string data)
- {
- Data = data;
- }
- }
- // A string type converter
- public class MyTypeConverter : TypeConverter
- {
- public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
- {
- if (sourceType == typeof(string))
- {
- return true;
- }
- return base.CanConvertFrom(context, sourceType);
- }
- public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
- {
- if (value is string)
- {
- return new ComplexTypeWithStringConverter((string)value);
- }
- return base.ConvertFrom(context, culture, value);
- }
- }
- class CustomModelBinderProvider : ModelBinderProvider
- {
- public override IModelBinder GetBinder(HttpActionContext actionContext, ModelBindingContext bindingContext)
- {
- throw new NotImplementedException();
- }
- }
- class CustomValueProviderFactory : ValueProviderFactory
- {
- public override IValueProvider GetValueProvider(HttpActionContext actionContext)
- {
- throw new NotImplementedException();
- }
- }
- }
- }