a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
1098 lines
50 KiB
C#
1098 lines
50 KiB
C#
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel.DataAnnotations;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Net.Http;
|
|
using System.Net.Http.Formatting;
|
|
using System.Net.Http.Headers;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Web.Http.Controllers;
|
|
using System.Web.Http.Routing;
|
|
using System.Web.Http.ValueProviders;
|
|
using Microsoft.TestCommon;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
using Xunit;
|
|
|
|
namespace System.Web.Http.ModelBinding
|
|
{
|
|
public class DefaultActionValueBinderTest
|
|
{
|
|
[Fact]
|
|
public void BindValuesAsync_Uses_DefaultValues()
|
|
{
|
|
// Arrange
|
|
HttpActionContext context = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("Get") });
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(context, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Dictionary<string, object> expectedResult = new Dictionary<string, object>();
|
|
expectedResult["id"] = 0;
|
|
expectedResult["firstName"] = "DefaultFirstName";
|
|
expectedResult["lastName"] = "DefaultLastName";
|
|
Assert.Equal(expectedResult, context.ActionArguments, new DictionaryEqualityComparer());
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_WithObjectContentInRequest_Works()
|
|
{
|
|
// Arrange
|
|
ActionValueItem cust = new ActionValueItem() { FirstName = "FirstName", LastName = "LastName", Id = 1 };
|
|
HttpActionContext context = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("PostComplexType") });
|
|
context.ControllerContext.Request = new HttpRequestMessage
|
|
{
|
|
Content = new ObjectContent<ActionValueItem>(cust, new JsonMediaTypeFormatter())
|
|
};
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(context, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
var result = context.ActionArguments;
|
|
Assert.Equal(1, result.Count);
|
|
var item = Assert.IsType<ActionValueItem>(result["item"]);
|
|
Assert.Equal(cust.FirstName, item.FirstName);
|
|
Assert.Equal(cust.LastName, item.LastName);
|
|
Assert.Equal(cust.Id, item.Id);
|
|
}
|
|
|
|
#region Query Strings
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_ConvertEmptyString()
|
|
{
|
|
HttpActionContext actionContext = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(new HttpRequestMessage()
|
|
{
|
|
Method = HttpMethod.Get,
|
|
RequestUri = new Uri("http://localhost?A1=&A2=&A3=&A4=")
|
|
}),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("GetTestEmptyString") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(actionContext, CancellationToken.None).Wait();
|
|
|
|
// Assert
|
|
ConvertEmptyStringContainer arg = (ConvertEmptyStringContainer) actionContext.ActionArguments["x"];
|
|
|
|
Assert.NotNull(arg);
|
|
Assert.Equal(String.Empty, arg.A1);
|
|
Assert.Null(arg.A2);
|
|
Assert.Null(arg.A3);
|
|
Assert.Null(arg.A4);
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Query_String_Values_To_Simple_Types()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
HttpActionContext actionContext = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(new HttpRequestMessage()
|
|
{
|
|
Method = HttpMethod.Get,
|
|
RequestUri = new Uri("http://localhost?id=5&firstName=queryFirstName&lastName=queryLastName")
|
|
}),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("Get") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(actionContext, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Dictionary<string, object> expectedResult = new Dictionary<string, object>();
|
|
expectedResult["id"] = 5;
|
|
expectedResult["firstName"] = "queryFirstName";
|
|
expectedResult["lastName"] = "queryLastName";
|
|
Assert.Equal(expectedResult, actionContext.ActionArguments, new DictionaryEqualityComparer());
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Query_String_Values_To_Simple_Types_With_FromUriAttribute()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
HttpActionContext actionContext = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(new HttpRequestMessage()
|
|
{
|
|
Method = HttpMethod.Get,
|
|
RequestUri = new Uri("http://localhost?id=5&firstName=queryFirstName&lastName=queryLastName")
|
|
}),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("GetFromUri") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(actionContext, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Dictionary<string, object> expectedResult = new Dictionary<string, object>();
|
|
expectedResult["id"] = 5;
|
|
expectedResult["firstName"] = "queryFirstName";
|
|
expectedResult["lastName"] = "queryLastName";
|
|
Assert.Equal(expectedResult, actionContext.ActionArguments, new DictionaryEqualityComparer());
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Query_String_Values_To_Complex_Types()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
HttpActionContext actionContext = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(new HttpRequestMessage()
|
|
{
|
|
Method = HttpMethod.Get,
|
|
RequestUri = new Uri("http://localhost?id=5&firstName=queryFirstName&lastName=queryLastName")
|
|
}),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("GetItem") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(actionContext, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.True(actionContext.ModelState.IsValid);
|
|
Assert.Equal(1, actionContext.ActionArguments.Count);
|
|
ActionValueItem deserializedActionValueItem = Assert.IsType<ActionValueItem>(actionContext.ActionArguments.First().Value);
|
|
Assert.Equal(5, deserializedActionValueItem.Id);
|
|
Assert.Equal("queryFirstName", deserializedActionValueItem.FirstName);
|
|
Assert.Equal("queryLastName", deserializedActionValueItem.LastName);
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Query_String_Values_To_Post_Complex_Types()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
HttpActionContext actionContext = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(new HttpRequestMessage()
|
|
{
|
|
Method = HttpMethod.Get,
|
|
RequestUri = new Uri("http://localhost?id=5&firstName=queryFirstName&lastName=queryLastName")
|
|
}),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("PostComplexTypeUri") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(actionContext, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.True(actionContext.ModelState.IsValid);
|
|
Assert.Equal(1, actionContext.ActionArguments.Count);
|
|
ActionValueItem deserializedActionValueItem = Assert.IsType<ActionValueItem>(actionContext.ActionArguments.First().Value);
|
|
Assert.Equal(5, deserializedActionValueItem.Id);
|
|
Assert.Equal("queryFirstName", deserializedActionValueItem.FirstName);
|
|
Assert.Equal("queryLastName", deserializedActionValueItem.LastName);
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Query_String_Values_To_Post_Enumerable_Complex_Types()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
HttpActionContext actionContext = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(new HttpRequestMessage()
|
|
{
|
|
Method = HttpMethod.Get,
|
|
RequestUri = new Uri("http://localhost?items[0].id=5&items[0].firstName=queryFirstName&items[0].lastName=queryLastName")
|
|
}),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("PostEnumerableUri") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(actionContext, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.True(actionContext.ModelState.IsValid);
|
|
Assert.Equal(1, actionContext.ActionArguments.Count);
|
|
IEnumerable<ActionValueItem> items = Assert.IsAssignableFrom<IEnumerable<ActionValueItem>>(actionContext.ActionArguments.First().Value);
|
|
ActionValueItem deserializedActionValueItem = items.First();
|
|
Assert.Equal(5, deserializedActionValueItem.Id);
|
|
Assert.Equal("queryFirstName", deserializedActionValueItem.FirstName);
|
|
Assert.Equal("queryLastName", deserializedActionValueItem.LastName);
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Query_String_Values_To_Post_Enumerable_Complex_Types_No_Index()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
HttpActionContext actionContext = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(new HttpRequestMessage()
|
|
{
|
|
Method = HttpMethod.Get,
|
|
RequestUri = new Uri("http://localhost?id=5&firstName=queryFirstName&items.lastName=queryLastName")
|
|
}),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("PostEnumerableUri") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(actionContext, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.True(actionContext.ModelState.IsValid);
|
|
Assert.Equal(1, actionContext.ActionArguments.Count);
|
|
IEnumerable<ActionValueItem> items = Assert.IsAssignableFrom<IEnumerable<ActionValueItem>>(actionContext.ActionArguments.First().Value);
|
|
Assert.Equal(0, items.Count()); // expect unsuccessful bind but proves we don't loop infinitely
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Query_String_Values_To_ComplexType_Using_Prefixes()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
HttpActionContext actionContext = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(new HttpRequestMessage()
|
|
{
|
|
Method = HttpMethod.Get,
|
|
RequestUri = new Uri("http://localhost?item.id=5&item.firstName=queryFirstName&item.lastName=queryLastName")
|
|
}),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("GetItem") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(actionContext, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.Equal(1, actionContext.ActionArguments.Count);
|
|
ActionValueItem deserializedActionValueItem = Assert.IsType<ActionValueItem>(actionContext.ActionArguments.First().Value);
|
|
Assert.Equal(5, deserializedActionValueItem.Id);
|
|
Assert.Equal("queryFirstName", deserializedActionValueItem.FirstName);
|
|
Assert.Equal("queryLastName", deserializedActionValueItem.LastName);
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Query_String_Values_To_ComplexType_Using_FromUriAttribute()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
HttpActionContext actionContext = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(new HttpRequestMessage()
|
|
{
|
|
Method = HttpMethod.Get,
|
|
RequestUri = new Uri("http://localhost?item.id=5&item.firstName=queryFirstName&item.lastName=queryLastName")
|
|
}),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("GetItemFromUri") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(actionContext, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.Equal(1, actionContext.ActionArguments.Count);
|
|
ActionValueItem deserializedActionValueItem = Assert.IsType<ActionValueItem>(actionContext.ActionArguments.First().Value);
|
|
Assert.Equal(5, deserializedActionValueItem.Id);
|
|
Assert.Equal("queryFirstName", deserializedActionValueItem.FirstName);
|
|
Assert.Equal("queryLastName", deserializedActionValueItem.LastName);
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Query_String_Values_Using_Custom_ValueProviderAttribute()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
HttpActionContext actionContext = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(new HttpRequestMessage()
|
|
{
|
|
Method = HttpMethod.Get
|
|
}),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("GetFromCustom") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(actionContext, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Dictionary<string, object> expectedResult = new Dictionary<string, object>();
|
|
expectedResult["id"] = 99;
|
|
expectedResult["firstName"] = "99";
|
|
expectedResult["lastName"] = "99";
|
|
Assert.Equal(expectedResult, actionContext.ActionArguments, new DictionaryEqualityComparer());
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Query_String_Values_Using_Prefix_To_Rename()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
HttpActionContext actionContext = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(new HttpRequestMessage()
|
|
{
|
|
Method = HttpMethod.Get,
|
|
RequestUri = new Uri("http://localhost?custid=5&first=renamedFirstName&last=renamedLastName")
|
|
// notice the query string names match the prefixes in GetFromNamed() and not the actual parameter names
|
|
}),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("GetFromNamed") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(actionContext, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Dictionary<string, object> expectedResult = new Dictionary<string, object>();
|
|
expectedResult["id"] = 5;
|
|
expectedResult["firstName"] = "renamedFirstName";
|
|
expectedResult["lastName"] = "renamedLastName";
|
|
Assert.Equal(expectedResult, actionContext.ActionArguments, new DictionaryEqualityComparer());
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Query_String_Values_To_Complex_Types_With_Validation_Error()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
HttpActionContext actionContext = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(new HttpRequestMessage()
|
|
{
|
|
Method = HttpMethod.Get,
|
|
RequestUri = new Uri("http://localhost?id=100&firstName=queryFirstName&lastName=queryLastName")
|
|
}),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("GetItem") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(actionContext, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.False(actionContext.ModelState.IsValid);
|
|
}
|
|
|
|
#endregion Query Strings
|
|
|
|
#region RouteData
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_RouteData_Values_To_Simple_Types()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
HttpRouteData route = new HttpRouteData(new HttpRoute());
|
|
route.Values.Add("id", 6);
|
|
route.Values.Add("firstName", "routeFirstName");
|
|
route.Values.Add("lastName", "routeLastName");
|
|
|
|
HttpActionContext controllerContext = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(route, new HttpRequestMessage()
|
|
{
|
|
Method = HttpMethod.Get,
|
|
RequestUri = new Uri("http://localhost")
|
|
}),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("Get") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(controllerContext, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Dictionary<string, object> expectedResult = new Dictionary<string, object>();
|
|
expectedResult["id"] = 6;
|
|
expectedResult["firstName"] = "routeFirstName";
|
|
expectedResult["lastName"] = "routeLastName";
|
|
Assert.Equal(expectedResult, controllerContext.ActionArguments, new DictionaryEqualityComparer());
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_RouteData_Values_To_Simple_Types_Using_FromUriAttribute()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
HttpRouteData route = new HttpRouteData(new HttpRoute());
|
|
route.Values.Add("id", 6);
|
|
route.Values.Add("firstName", "routeFirstName");
|
|
route.Values.Add("lastName", "routeLastName");
|
|
|
|
HttpActionContext controllerContext = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(route, new HttpRequestMessage()
|
|
{
|
|
Method = HttpMethod.Get,
|
|
RequestUri = new Uri("http://localhost")
|
|
}),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("Get") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(controllerContext, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Dictionary<string, object> expectedResult = new Dictionary<string, object>();
|
|
expectedResult["id"] = 6;
|
|
expectedResult["firstName"] = "routeFirstName";
|
|
expectedResult["lastName"] = "routeLastName";
|
|
Assert.Equal(expectedResult, controllerContext.ActionArguments, new DictionaryEqualityComparer());
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_RouteData_Values_To_Complex_Types()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
HttpRouteData route = new HttpRouteData(new HttpRoute());
|
|
route.Values.Add("id", 6);
|
|
route.Values.Add("firstName", "routeFirstName");
|
|
route.Values.Add("lastName", "routeLastName");
|
|
|
|
HttpActionContext controllerContext = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(route, new HttpRequestMessage()
|
|
{
|
|
Method = HttpMethod.Get,
|
|
RequestUri = new Uri("http://localhost")
|
|
}),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("GetItem") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(controllerContext, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.Equal(1, controllerContext.ActionArguments.Count);
|
|
ActionValueItem deserializedActionValueItem = Assert.IsType<ActionValueItem>(controllerContext.ActionArguments.First().Value);
|
|
Assert.Equal(6, deserializedActionValueItem.Id);
|
|
Assert.Equal("routeFirstName", deserializedActionValueItem.FirstName);
|
|
Assert.Equal("routeLastName", deserializedActionValueItem.LastName);
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_RouteData_Values_To_Complex_Types_Using_FromUriAttribute()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
HttpRouteData route = new HttpRouteData(new HttpRoute());
|
|
route.Values.Add("id", 6);
|
|
route.Values.Add("firstName", "routeFirstName");
|
|
route.Values.Add("lastName", "routeLastName");
|
|
|
|
HttpActionContext controllerContext = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(route, new HttpRequestMessage()
|
|
{
|
|
Method = HttpMethod.Get,
|
|
RequestUri = new Uri("http://localhost")
|
|
}),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("GetItemFromUri") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(controllerContext, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.Equal(1, controllerContext.ActionArguments.Count);
|
|
ActionValueItem deserializedActionValueItem = Assert.IsType<ActionValueItem>(controllerContext.ActionArguments.First().Value);
|
|
Assert.Equal(6, deserializedActionValueItem.Id);
|
|
Assert.Equal("routeFirstName", deserializedActionValueItem.FirstName);
|
|
Assert.Equal("routeLastName", deserializedActionValueItem.LastName);
|
|
}
|
|
|
|
#endregion RouteData
|
|
|
|
#region ControllerContext
|
|
[Fact]
|
|
public void BindValuesAsync_ControllerContext_CancellationToken()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
HttpActionContext actionContext = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(new HttpRequestMessage()
|
|
{
|
|
Method = HttpMethod.Get
|
|
}),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("GetFromCancellationToken") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(actionContext, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.Equal(1, actionContext.ActionArguments.Count);
|
|
Assert.Equal(cancellationToken, actionContext.ActionArguments.First().Value);
|
|
}
|
|
#endregion ControllerContext
|
|
|
|
#region Body
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Body_To_Complex_Type_Json()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
string jsonString = "{\"Id\":\"7\",\"FirstName\":\"testFirstName\",\"LastName\":\"testLastName\"}";
|
|
StringContent stringContent = new StringContent(jsonString, Encoding.UTF8, "application/json");
|
|
|
|
HttpRequestMessage request = new HttpRequestMessage() { Content = stringContent };
|
|
HttpActionContext context = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(request),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("PostComplexType") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(context, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.Equal(1, context.ActionArguments.Count);
|
|
ActionValueItem deserializedActionValueItem = Assert.IsAssignableFrom<ActionValueItem>(context.ActionArguments.First().Value);
|
|
Assert.Equal(7, deserializedActionValueItem.Id);
|
|
Assert.Equal("testFirstName", deserializedActionValueItem.FirstName);
|
|
Assert.Equal("testLastName", deserializedActionValueItem.LastName);
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Body_To_Complex_Type_Json_With_Validation_Error()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
string jsonString = "{\"Id\":\"100\",\"FirstName\":\"testFirstName\",\"LastName\":\"testLastName\"}";
|
|
StringContent stringContent = new StringContent(jsonString, Encoding.UTF8, "application/json");
|
|
|
|
HttpRequestMessage request = new HttpRequestMessage() { Content = stringContent };
|
|
HttpActionContext context = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(request),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("PostComplexType") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(context, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.False(context.ModelState.IsValid);
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Body_To_Complex_Type_FormUrlEncoded()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
string formUrlEncodedString = "Id=7&FirstName=testFirstName&LastName=testLastName";
|
|
StringContent stringContent = new StringContent(formUrlEncodedString, Encoding.UTF8, "application/x-www-form-urlencoded");
|
|
|
|
HttpRequestMessage request = new HttpRequestMessage() { Content = stringContent };
|
|
HttpActionContext context = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(request),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("PostComplexType") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(context, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.Equal(1, context.ActionArguments.Count);
|
|
ActionValueItem deserializedActionValueItem = Assert.IsAssignableFrom<ActionValueItem>(context.ActionArguments.First().Value);
|
|
Assert.Equal(7, deserializedActionValueItem.Id);
|
|
Assert.Equal("testFirstName", deserializedActionValueItem.FirstName);
|
|
Assert.Equal("testLastName", deserializedActionValueItem.LastName);
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Body_To_Complex_Type_FormUrlEncoded_With_Validation_Error()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
string formUrlEncodedString = "Id=101&FirstName=testFirstName&LastName=testLastName";
|
|
StringContent stringContent = new StringContent(formUrlEncodedString, Encoding.UTF8, "application/x-www-form-urlencoded");
|
|
|
|
HttpRequestMessage request = new HttpRequestMessage() { Content = stringContent };
|
|
HttpActionContext context = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(request),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("PostComplexType") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(context, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.False(context.ModelState.IsValid);
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Body_To_Complex_Type_Xml()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
MediaTypeHeaderValue mediaType = new MediaTypeHeaderValue("application/xml");
|
|
ActionValueItem item = new ActionValueItem() { Id = 7, FirstName = "testFirstName", LastName = "testLastName" };
|
|
ObjectContent<ActionValueItem> tempContent = new ObjectContent<ActionValueItem>(item, new XmlMediaTypeFormatter());
|
|
StringContent stringContent = new StringContent(tempContent.ReadAsStringAsync().Result);
|
|
stringContent.Headers.ContentType = mediaType;
|
|
HttpRequestMessage request = new HttpRequestMessage() { Content = stringContent };
|
|
HttpActionContext context = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(request),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("PostComplexType") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(context, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.Equal(1, context.ActionArguments.Count);
|
|
ActionValueItem deserializedActionValueItem = Assert.IsAssignableFrom<ActionValueItem>(context.ActionArguments.First().Value);
|
|
Assert.Equal(item.Id, deserializedActionValueItem.Id);
|
|
Assert.Equal(item.FirstName, deserializedActionValueItem.FirstName);
|
|
Assert.Equal(item.LastName, deserializedActionValueItem.LastName);
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Body_To_Complex_Type_Xml_Structural()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
MediaTypeHeaderValue mediaType = new MediaTypeHeaderValue("application/xml");
|
|
|
|
// Test sending from a non .NET type (raw xml).
|
|
// The default XML serializer requires that the xml root name matches the C# class name.
|
|
string xmlSource =
|
|
@"<ActionValueItem xmlns='http://schemas.datacontract.org/2004/07/System.Web.Http.ModelBinding' xmlns:i='http://www.w3.org/2001/XMLSchema-instance'>
|
|
<FirstName>testFirstName</FirstName>
|
|
<Id>7</Id>
|
|
<LastName>testLastName</LastName>
|
|
</ActionValueItem>".Replace('\'', '"');
|
|
|
|
StringContent stringContent = new StringContent(xmlSource);
|
|
stringContent.Headers.ContentType = mediaType;
|
|
HttpRequestMessage request = new HttpRequestMessage() { Content = stringContent };
|
|
HttpActionContext context = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(request),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("PostComplexType") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(context, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.Equal(1, context.ActionArguments.Count);
|
|
ActionValueItem deserializedActionValueItem = Assert.IsAssignableFrom<ActionValueItem>(context.ActionArguments.First().Value);
|
|
Assert.Equal(7, deserializedActionValueItem.Id);
|
|
Assert.Equal("testFirstName", deserializedActionValueItem.FirstName);
|
|
Assert.Equal("testLastName", deserializedActionValueItem.LastName);
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Body_To_Complex_Type_Xml_With_Validation_Error()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
MediaTypeHeaderValue mediaType = new MediaTypeHeaderValue("application/xml");
|
|
ActionValueItem item = new ActionValueItem() { Id = 101, FirstName = "testFirstName", LastName = "testLastName" };
|
|
var tempContent = new ObjectContent<ActionValueItem>(item, new XmlMediaTypeFormatter());
|
|
StringContent stringContent = new StringContent(tempContent.ReadAsStringAsync().Result);
|
|
stringContent.Headers.ContentType = mediaType;
|
|
HttpRequestMessage request = new HttpRequestMessage() { Content = stringContent };
|
|
HttpActionContext context = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(request),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("PostComplexType") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(context, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.False(context.ModelState.IsValid);
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Body_To_Complex_And_Uri_To_Simple()
|
|
{
|
|
// Arrange
|
|
string jsonString = "{\"Id\":\"7\",\"FirstName\":\"testFirstName\",\"LastName\":\"testLastName\"}";
|
|
StringContent stringContent = new StringContent(jsonString, Encoding.UTF8, "application/json");
|
|
|
|
HttpRequestMessage request = new HttpRequestMessage()
|
|
{
|
|
RequestUri = new Uri("http://localhost/ActionValueController/PostFromBody?id=123"),
|
|
Content = stringContent
|
|
};
|
|
|
|
HttpActionContext context = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(request),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("PostFromBodyAndUri") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(context, CancellationToken.None).Wait();
|
|
|
|
// Assert
|
|
Assert.Equal(2, context.ActionArguments.Count);
|
|
Assert.Equal(123, context.ActionArguments["id"]);
|
|
|
|
ActionValueItem deserializedActionValueItem = Assert.IsAssignableFrom<ActionValueItem>(context.ActionArguments["item"]);
|
|
Assert.Equal(7, deserializedActionValueItem.Id);
|
|
Assert.Equal("testFirstName", deserializedActionValueItem.FirstName);
|
|
Assert.Equal("testLastName", deserializedActionValueItem.LastName);
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Body_To_Complex_Type_Using_FromBodyAttribute()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
string jsonString = "{\"Id\":\"7\",\"FirstName\":\"testFirstName\",\"LastName\":\"testLastName\"}";
|
|
StringContent stringContent = new StringContent(jsonString, Encoding.UTF8, "application/json");
|
|
|
|
HttpRequestMessage request = new HttpRequestMessage() { Content = stringContent };
|
|
|
|
HttpActionContext context = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(request),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("PostFromBody") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(context, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.Equal(1, context.ActionArguments.Count);
|
|
ActionValueItem deserializedActionValueItem = Assert.IsAssignableFrom<ActionValueItem>(context.ActionArguments.First().Value);
|
|
Assert.Equal(7, deserializedActionValueItem.Id);
|
|
Assert.Equal("testFirstName", deserializedActionValueItem.FirstName);
|
|
Assert.Equal("testLastName", deserializedActionValueItem.LastName);
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Body_To_Complex_Type_Using_Formatter_To_Deserialize()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
string jsonString = "{\"Id\":\"7\",\"FirstName\":\"testFirstName\",\"LastName\":\"testLastName\"}";
|
|
StringContent stringContent = new StringContent(jsonString, Encoding.UTF8, "application/json");
|
|
|
|
HttpRequestMessage request = new HttpRequestMessage() { Content = stringContent };
|
|
HttpActionContext context = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(request),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("PostComplexType") });
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(context, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.Equal(1, context.ActionArguments.Count);
|
|
ActionValueItem deserializedActionValueItem = Assert.IsAssignableFrom<ActionValueItem>(context.ActionArguments.First().Value);
|
|
Assert.Equal(7, deserializedActionValueItem.Id);
|
|
Assert.Equal("testFirstName", deserializedActionValueItem.FirstName);
|
|
Assert.Equal("testLastName", deserializedActionValueItem.LastName);
|
|
}
|
|
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Body_To_IEnumerable_Complex_Type_Json()
|
|
{
|
|
// ModelBinding will bind T to IEnumerable<T>, but JSON.Net won't. So enclose JSON in [].
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
string jsonString = "[{\"Id\":\"7\",\"FirstName\":\"testFirstName\",\"LastName\":\"testLastName\"}]";
|
|
StringContent stringContent = new StringContent(jsonString, Encoding.UTF8, "application/json");
|
|
|
|
HttpRequestMessage request = new HttpRequestMessage() { Content = stringContent };
|
|
HttpActionContext context = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(request),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("PostEnumerable") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(context, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.Equal(1, context.ActionArguments.Count);
|
|
IEnumerable<ActionValueItem> items = Assert.IsAssignableFrom<IEnumerable<ActionValueItem>>(context.ActionArguments.First().Value);
|
|
ActionValueItem deserializedActionValueItem = items.First();
|
|
Assert.Equal(7, deserializedActionValueItem.Id);
|
|
Assert.Equal("testFirstName", deserializedActionValueItem.FirstName);
|
|
Assert.Equal("testLastName", deserializedActionValueItem.LastName);
|
|
}
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_Body_To_JToken()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
MediaTypeHeaderValue mediaType = new MediaTypeHeaderValue("application/json");
|
|
ActionValueItem item = new ActionValueItem() { Id = 7, FirstName = "testFirstName", LastName = "testLastName" };
|
|
string json = "{\"a\":123,\"b\":[false,null,12.34]}";
|
|
JToken jt = JToken.Parse(json);
|
|
var tempContent = new ObjectContent<JToken>(jt, new JsonMediaTypeFormatter());
|
|
StringContent stringContent = new StringContent(tempContent.ReadAsStringAsync().Result);
|
|
stringContent.Headers.ContentType = mediaType;
|
|
HttpRequestMessage request = new HttpRequestMessage() { Content = stringContent };
|
|
HttpActionContext context = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(request),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("PostJsonValue") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(context, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Assert.Equal(1, context.ActionArguments.Count);
|
|
JToken deserializedJsonValue = Assert.IsAssignableFrom<JToken>(context.ActionArguments.First().Value);
|
|
string deserializedJsonAsString = deserializedJsonValue.ToString(Formatting.None);
|
|
Assert.Equal(json, deserializedJsonAsString);
|
|
}
|
|
|
|
#endregion Body
|
|
|
|
[Fact]
|
|
public void BindValuesAsync_FromUriAttribute_DecoratedOn_Type()
|
|
{
|
|
// Arrange
|
|
CancellationToken cancellationToken = new CancellationToken();
|
|
HttpActionContext actionContext = ContextUtil.CreateActionContext(
|
|
ContextUtil.CreateControllerContext(new HttpRequestMessage()
|
|
{
|
|
Method = new HttpMethod("Patch"),
|
|
RequestUri = new Uri("http://localhost?x=123&y=456&data.description=mypoint")
|
|
}),
|
|
new ReflectedHttpActionDescriptor() { MethodInfo = typeof(ActionValueController).GetMethod("Patch") });
|
|
|
|
DefaultActionValueBinder provider = new DefaultActionValueBinder();
|
|
|
|
// Act
|
|
provider.BindValuesAsync(actionContext, cancellationToken).Wait();
|
|
|
|
// Assert
|
|
Dictionary<string, object> expectedResult = new Dictionary<string, object>();
|
|
expectedResult["point"] = new Point { X = 123, Y = 456, Data = new Data { Description = "mypoint" } };
|
|
Assert.Equal(expectedResult, actionContext.ActionArguments, new DictionaryEqualityComparer());
|
|
}
|
|
}
|
|
|
|
[FromUri]
|
|
public class Point
|
|
{
|
|
public int X { get; set; }
|
|
public int Y { get; set; }
|
|
public Data Data { get; set; }
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
Point other = obj as Point;
|
|
if (other != null)
|
|
{
|
|
return other.X == X && other.Y == Y && other.Data.Description == other.Data.Description;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return base.GetHashCode();
|
|
}
|
|
}
|
|
|
|
public class Data
|
|
{
|
|
public string Description { get; set; }
|
|
}
|
|
|
|
public class ActionValueController : ApiController
|
|
{
|
|
// Demonstrates complex parameter that has FromUri declared on the type
|
|
public void Patch(Point point) { }
|
|
|
|
// Demonstrates parameter that can come from route, query string, or defaults
|
|
public ActionValueItem Get(int id = 0, string firstName = "DefaultFirstName", string lastName = "DefaultLastName")
|
|
{
|
|
return new ActionValueItem() { Id = id, FirstName = firstName, LastName = lastName };
|
|
}
|
|
|
|
// Demonstrates an explicit override to obtain parameters from URL
|
|
public ActionValueItem GetFromUri([FromUri] int id = 0,
|
|
[FromUri] string firstName = "DefaultFirstName",
|
|
[FromUri] string lastName = "DefaultLastName")
|
|
{
|
|
return new ActionValueItem() { Id = id, FirstName = firstName, LastName = lastName };
|
|
}
|
|
|
|
|
|
// Complex objects default to body. But we can bind from URI with an attribute.
|
|
public ActionValueItem GetItem([FromUri] ActionValueItem item)
|
|
{
|
|
return item;
|
|
}
|
|
|
|
// Demonstrates ModelBinding a Item object explicitly from Uri
|
|
public ActionValueItem GetItemFromUri([FromUri] ActionValueItem item)
|
|
{
|
|
return item;
|
|
}
|
|
|
|
// Demonstrates use of renaming parameters via name
|
|
public ActionValueItem GetFromNamed([FromUri(Name = "custID")] int id,
|
|
[FromUri(Name = "first")] string firstName,
|
|
[FromUri(Name = "last")] string lastName)
|
|
{
|
|
return new ActionValueItem() { Id = id, FirstName = firstName, LastName = lastName };
|
|
}
|
|
|
|
|
|
public void GetTestEmptyString([FromUri] ConvertEmptyStringContainer x)
|
|
{
|
|
}
|
|
|
|
// Demonstrates use of custom ValueProvider via attribute
|
|
public ActionValueItem GetFromCustom([ValueProvider(typeof(ActionValueControllerValueProviderFactory), Name = "id")] int id,
|
|
[ValueProvider(typeof(ActionValueControllerValueProviderFactory), Name = "customFirstName")] string firstName,
|
|
[ValueProvider(typeof(ActionValueControllerValueProviderFactory), Name = "customLastName")] string lastName)
|
|
{
|
|
return new ActionValueItem() { Id = id, FirstName = firstName, LastName = lastName };
|
|
}
|
|
|
|
// Demonstrates ModelBinding to the CancellationToken of the current request
|
|
public string GetFromCancellationToken(CancellationToken cancellationToken)
|
|
{
|
|
return cancellationToken.ToString();
|
|
}
|
|
|
|
// Demonstrates ModelBinding to the ModelState of the current request
|
|
public string GetFromModelState(ModelState modelState)
|
|
{
|
|
return modelState.ToString();
|
|
}
|
|
|
|
// Demonstrates binding to complex type from body
|
|
public ActionValueItem PostComplexType(ActionValueItem item)
|
|
{
|
|
return item;
|
|
}
|
|
|
|
// Demonstrates binding to complex type from uri
|
|
public ActionValueItem PostComplexTypeUri([FromUri] ActionValueItem item)
|
|
{
|
|
return item;
|
|
}
|
|
|
|
// Demonstrates binding to IEnumerable of complex type from body or Uri
|
|
public ActionValueItem PostEnumerable(IEnumerable<ActionValueItem> items)
|
|
{
|
|
return items.FirstOrDefault();
|
|
}
|
|
|
|
// Demonstrates binding to IEnumerable of complex type from body or Uri
|
|
public ActionValueItem PostEnumerableUri([FromUri] IEnumerable<ActionValueItem> items)
|
|
{
|
|
return items.FirstOrDefault();
|
|
}
|
|
|
|
// Demonstrates binding to JsonValue from body
|
|
public JToken PostJsonValue(JToken jsonValue)
|
|
{
|
|
return jsonValue;
|
|
}
|
|
|
|
// Demonstrate what we expect to be the common default scenario. No attributes are required.
|
|
// A complex object comes from the body, and simple objects come from the URI.
|
|
public ActionValueItem PostFromBodyAndUri(int id, ActionValueItem item)
|
|
{
|
|
return item;
|
|
}
|
|
|
|
// Demonstrates binding to complex type explicitly marked as coming from body
|
|
public ActionValueItem PostFromBody([FromBody] ActionValueItem item)
|
|
{
|
|
return item;
|
|
}
|
|
|
|
// Demonstrates how body can be shredded to name/value pairs to bind to simple types
|
|
public ActionValueItem PostToSimpleTypes(int id, string firstName, string lastName)
|
|
{
|
|
return new ActionValueItem() { Id = id, FirstName = firstName, LastName = lastName };
|
|
}
|
|
|
|
// Demonstrates binding to ObjectContent<T> from request body
|
|
public ActionValueItem PostObjectContentOfItem(ObjectContent<ActionValueItem> item)
|
|
{
|
|
return item.ReadAsAsync<ActionValueItem>().Result;
|
|
}
|
|
|
|
public class ActionValueControllerValueProviderFactory : ValueProviderFactory
|
|
{
|
|
public override IValueProvider GetValueProvider(HttpActionContext actionContext)
|
|
{
|
|
return new ActionValueControllerValueProvider();
|
|
}
|
|
}
|
|
|
|
public class ActionValueControllerValueProvider : IValueProvider
|
|
{
|
|
public bool ContainsPrefix(string prefix)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
public ValueProviderResult GetValue(string key)
|
|
{
|
|
return new ValueProviderResult("99", "99", CultureInfo.CurrentCulture);
|
|
}
|
|
}
|
|
}
|
|
|
|
static class DefaultActionValueBinderExtensions
|
|
{
|
|
public static Task BindValuesAsync(this DefaultActionValueBinder binder, HttpActionContext actionContext, CancellationToken cancellationToken)
|
|
{
|
|
HttpActionBinding binding = binder.GetBinding(actionContext.ActionDescriptor);
|
|
return binding.ExecuteBindingAsync(actionContext, cancellationToken);
|
|
}
|
|
}
|
|
|
|
public class ActionValueItem
|
|
{
|
|
[Range(0, 99)]
|
|
public int Id { get; set; }
|
|
public string FirstName { get; set; }
|
|
public string LastName { get; set; }
|
|
}
|
|
|
|
// Test variants of converting empty string to null.
|
|
// Pass each property the empty string.
|
|
public class ConvertEmptyStringContainer
|
|
{
|
|
[DisplayFormat(ConvertEmptyStringToNull = false)]
|
|
public string A1 { get; set; } // ""
|
|
|
|
[DisplayFormat(ConvertEmptyStringToNull = true)]
|
|
public string A2 { get; set; } // Null
|
|
|
|
[DisplayFormat]
|
|
public string A3 { get; set; } // Null
|
|
|
|
public string A4 { get; set; } // Null
|
|
}
|
|
}
|