Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@ -0,0 +1,122 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Text;
using Xunit;
using Xunit.Extensions;
namespace System.Web.Http.ModelBinding
{
/// <summary>
/// End to end functional tests for model binding via request body
/// </summary>
public class BodyBindingTests : ModelBindingTests
{
[Fact]
public void Body_Bad_Input_Receives_Validation_Error()
{
// Arrange
string formUrlEncodedString = "Id=101&Name=testFirstNameTooLong";
StringContent stringContent = new StringContent(formUrlEncodedString, Encoding.UTF8, "application/x-www-form-urlencoded");
HttpRequestMessage request = new HttpRequestMessage()
{
RequestUri = new Uri(baseAddress + "ModelBinding/PostComplexWithValidation"),
Method = HttpMethod.Post,
Content = stringContent,
};
// Act
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
Assert.Equal("Failed to bind customer.RequiredValue. The errors are:\nErrorMessage: The RequiredValue property is required.\nFailed to bind customer.Name. The errors are:\nErrorMessage: The field Name must be a string with a maximum length of 6.\n", response.Content.ReadAsStringAsync().Result);
}
[Fact]
public void Body_Good_Input_Succeed()
{
// Arrange
string formUrlEncodedString = "Id=111&Name=John&RequiredValue=9";
StringContent stringContent = new StringContent(formUrlEncodedString, Encoding.UTF8, "application/x-www-form-urlencoded");
HttpRequestMessage request = new HttpRequestMessage()
{
RequestUri = new Uri(baseAddress + "ModelBinding/PostComplexWithValidation"),
Method = HttpMethod.Post,
Content = stringContent,
};
// Act
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal("111", response.Content.ReadAsStringAsync().Result);
}
[Theory]
[InlineData("PostComplexType", "application/json")]
[InlineData("PostComplexType", "application/xml")]
[InlineData("PostComplexTypeFromBody", "application/json")]
[InlineData("PostComplexTypeFromBody", "application/xml")]
public void Body_Binds_ComplexType_Type_Key_Value_Read(string action, string mediaType)
{
// Arrange
ModelBindOrder expectedItem = new ModelBindOrder()
{
ItemName = "Bike",
Quantity = 1,
Customer = new ModelBindCustomer { Name = "Fred" }
};
var formatter = new MediaTypeFormatterCollection().FindWriter(typeof(ModelBindOrder), new MediaTypeHeaderValue(mediaType));
HttpRequestMessage request = new HttpRequestMessage
{
Content = new ObjectContent<ModelBindOrder>(expectedItem, formatter),
RequestUri = new Uri(baseAddress + String.Format("ModelBinding/{0}", action)),
Method = HttpMethod.Post,
};
// Act
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
ModelBindOrder actualItem = response.Content.ReadAsAsync<ModelBindOrder>().Result;
Assert.Equal<ModelBindOrder>(expectedItem, actualItem, new ModelBindOrderEqualityComparer());
}
[Theory]
[InlineData("PostComplexType", "application/json")]
[InlineData("PostComplexType", "application/xml")]
[InlineData("PostComplexTypeFromBody", "application/json")]
[InlineData("PostComplexTypeFromBody", "application/xml")]
public void Body_Binds_ComplexType_Type_Whole_Body_Read(string action, string mediaType)
{
// Arrange
ModelBindOrder expectedItem = new ModelBindOrder()
{
ItemName = "Bike",
Quantity = 1,
Customer = new ModelBindCustomer { Name = "Fred" }
};
var formatter = new MediaTypeFormatterCollection().FindWriter(typeof(ModelBindOrder), new MediaTypeHeaderValue(mediaType));
HttpRequestMessage request = new HttpRequestMessage
{
Content = new ObjectContent<ModelBindOrder>(expectedItem, formatter),
RequestUri = new Uri(baseAddress + String.Format("ModelBinding/{0}", action)),
Method = HttpMethod.Post,
};
// Act
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
ModelBindOrder actualItem = response.Content.ReadAsAsync<ModelBindOrder>().Result;
Assert.Equal<ModelBindOrder>(expectedItem, actualItem, new ModelBindOrderEqualityComparer());
}
}
}

View File

@ -0,0 +1,34 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Net.Http;
using Xunit;
namespace System.Web.Http.ModelBinding
{
/// <summary>
/// End to end functional tests for model binding via custom providers
/// </summary>
public class CustomBindingTests : ModelBindingTests
{
[Fact]
public void Custom_ValueProvider_Binds_Simple_Types_Get()
{
// Arrange
HttpRequestMessage request = new HttpRequestMessage()
{
RequestUri = new Uri(baseAddress + String.Format("ModelBinding/{0}", "GetIntCustom")),
Method = HttpMethod.Get
};
request.Headers.Add("value", "5");
// Act
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
string responseString = response.Content.ReadAsStringAsync().Result;
Assert.Equal<string>("5", responseString);
}
}
}

View File

@ -0,0 +1,95 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Web.Http.SelfHost;
using Xunit;
using Xunit.Extensions;
namespace System.Web.Http.ModelBinding
{
/// <summary>
/// Tests actions that directly use HttpRequestMessage parameters
/// </summary>
public class HttpContentBindingTests : IDisposable
{
public HttpContentBindingTests()
{
this.SetupHost();
}
public void Dispose()
{
this.CleanupHost();
}
[Theory]
[InlineData("application/xml")]
[InlineData("text/xml")]
[InlineData("application/json")]
[InlineData("text/json")]
public void Action_Directly_Reads_HttpRequestMessage(string mediaType)
{
Order order = new Order() { OrderId = "99", OrderValue = 100.0 };
var formatter = new MediaTypeFormatterCollection().FindWriter(typeof(Order), new MediaTypeHeaderValue(mediaType));
HttpRequestMessage request = new HttpRequestMessage()
{
Content = new ObjectContent<Order>(order, formatter, mediaType),
RequestUri = new Uri(baseAddress + "/HttpContentBinding/HandleMessage"),
Method = HttpMethod.Post
};
HttpResponseMessage response = httpClient.SendAsync(request).Result;
Order receivedOrder = response.Content.ReadAsAsync<Order>().Result;
Assert.Equal(order.OrderId, receivedOrder.OrderId);
Assert.Equal(order.OrderValue, receivedOrder.OrderValue);
}
private HttpSelfHostServer server = null;
private string baseAddress = null;
private HttpClient httpClient = null;
private void SetupHost()
{
httpClient = new HttpClient();
baseAddress = String.Format("http://{0}", Environment.MachineName);
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration(baseAddress);
config.Routes.MapHttpRoute("Default", "{controller}/{action}", new { controller = "HttpContentBinding", action = "HandleMessage" });
server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();
}
private void CleanupHost()
{
if (server != null)
{
server.CloseAsync().Wait();
}
}
}
public class Order
{
public string OrderId { get; set; }
public double OrderValue { get; set; }
}
public class HttpContentBindingController : ApiController
{
[HttpPost]
public HttpResponseMessage HandleMessage()
{
Order order = Request.Content.ReadAsAsync<Order>().Result;
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ObjectContent<Order>(order, new JsonMediaTypeFormatter())
};
}
}
}

View File

@ -0,0 +1,257 @@
// 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;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
using System.Web.Http.ValueProviders;
using Xunit;
namespace System.Web.Http.ModelBinding
{
public class ModelBindingController : ApiController
{
public string GetString(string value)
{
return value;
}
public string GetStringFromRoute(string controller, string action)
{
return controller + ":" + action;
}
public int GetInt(int value)
{
return value;
}
public int GetIntWithDefault(int value = -1)
{
return value;
}
public int GetIntFromUri([FromUri] int value)
{
return value;
}
public int GetIntPrefixed([FromUri(Name = "somePrefix")] int value)
{
return value;
}
public int GetIntCustom([ValueProvider(typeof(RequestHeadersValueProviderFactory))] int value)
{
return value;
}
public Task<int> GetIntAsync(int value, CancellationToken token)
{
Assert.NotNull(token);
TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
tcs.TrySetResult(value);
return tcs.Task;
}
public bool GetBool(bool value)
{
return value;
}
public ModelBindOrder GetComplexType(ModelBindOrder item)
{
return item;
}
public ModelBindOrder GetComplexTypeFromUri([FromUri] ModelBindOrder item)
{
return item;
}
public string PostString(string value)
{
return value;
}
public int PostInt(int value)
{
return value;
}
public HttpResponseMessage PostComplexWithValidation(CustomerNameMax6 customer)
{
string errors = String.Empty;
foreach (var kv in this.ModelState)
{
int errorCount = kv.Value.Errors.Count;
if (errorCount > 0)
{
errors += String.Format("Failed to bind {0}. The errors are:\n", kv.Key);
for (int i = 0; i < errorCount; i++)
{
ModelError error = kv.Value.Errors[i];
errors += "ErrorMessage: " + error.ErrorMessage + "\n";
if (error.Exception != null)
{
errors += "Exception" + error.Exception + "\n";
}
}
}
}
if (errors != String.Empty)
{
// Has validation failure
// TODO, 334736, support HttpResponseException which takes ModelState
// throw new HttpResponseException(this.ModelState);
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.BadRequest);
response.Content = new StringContent(errors);
throw new HttpResponseException(response);
}
else
{
// happy path
return Request.CreateResponse<int>(HttpStatusCode.OK, customer.Id);
}
}
public int PostIntFromUri([FromUri] int value)
{
return value;
}
public int PostIntFromBody([FromBody] int value)
{
return value;
}
public int PostIntUriPrefixed([FromUri(Name = "somePrefix")] int value)
{
return value;
}
public bool PostBool(bool value)
{
return value;
}
public int PostIntArray([FromUri] int[] value)
{
return value.Sum();
}
public ModelBindOrder PostComplexType(ModelBindOrder item)
{
return item;
}
public ModelBindOrder PostComplexTypeFromUri([FromUri] ModelBindOrder item)
{
return item;
}
public ModelBindOrder PostComplexTypeFromBody([FromBody] ModelBindOrder item)
{
return item;
}
// check if HttpRequestMessage prevents binding other parameters
public int PostComplexTypeHttpRequestMessage(HttpRequestMessage request, ModelBindOrder order)
{
return Int32.Parse(order.ItemName) + order.Quantity;
}
}
public class CustomerNameMax6
{
[Required]
[StringLength(6)]
public string Name { get; set; }
public int Id { get; set; }
[Required]
public int RequiredValue { get; set; }
}
public class ModelBindCustomer
{
public string Name { get; set; }
}
public class ModelBindOrder
{
public string ItemName { get; set; }
public int Quantity { get; set; }
public ModelBindCustomer Customer { get; set; }
}
public class ModelBindOrderEqualityComparer : IEqualityComparer<ModelBindOrder>
{
public bool Equals(ModelBindOrder x, ModelBindOrder y)
{
Assert.True(x != null, "Expected ModelBindOrder cannot be null.");
Assert.True(y != null, "Actual ModelBindOrder was null.");
Assert.Equal<string>(x.ItemName, y.ItemName);
Assert.Equal<int>(x.Quantity, y.Quantity);
if (x.Customer != null)
{
Assert.True(y.Customer != null, "Actual Customer was null but expected was " + x.Customer.Name);
}
else if (x.Customer == null)
{
Assert.True(y.Customer == null, "Actual Customer was not null but should have been.");
}
else
{
Assert.True(String.Equals(x.Customer.Name, y.Customer.Name, StringComparison.Ordinal), String.Format("Expected Customer.Name '{0}' but actual was '{1}'", x.Customer.Name, y.Customer.Name));
}
return true;
}
public int GetHashCode(ModelBindOrder obj)
{
return obj.GetHashCode();
}
}
public class RequestHeadersValueProviderFactory : ValueProviderFactory
{
public override IValueProvider GetValueProvider(HttpActionContext actionContext)
{
return new RequestHeaderValueProvider(actionContext);
}
}
public class RequestHeaderValueProvider : IValueProvider
{
HttpActionContext _actionContext;
public RequestHeaderValueProvider(HttpActionContext actionContext)
{
_actionContext = actionContext;
}
public bool ContainsPrefix(string prefix)
{
return _actionContext.ControllerContext.Request.Headers.Contains(prefix);
}
public ValueProviderResult GetValue(string key)
{
string result = _actionContext.ControllerContext.Request.Headers.GetValues(key).FirstOrDefault();
return result == null
? null
: new ValueProviderResult(result, result, CultureInfo.CurrentCulture);
}
}
}

View File

@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Net.Http;
using System.Web.Http.SelfHost;
namespace System.Web.Http.ModelBinding
{
/// <summary>
/// End to end functional tests for model binding
/// </summary>
public abstract class ModelBindingTests : IDisposable
{
protected HttpSelfHostServer server = null;
protected HttpSelfHostConfiguration configuration = null;
protected string baseAddress = null;
protected HttpClient httpClient = null;
protected ModelBindingTests()
{
this.SetupHost();
}
public void Dispose()
{
this.CleanupHost();
}
public void SetupHost()
{
httpClient = new HttpClient();
baseAddress = String.Format("http://{0}/", Environment.MachineName);
configuration = new HttpSelfHostConfiguration(baseAddress);
configuration.Routes.MapHttpRoute("Default", "{controller}/{action}", new { controller = "ModelBinding" });
server = new HttpSelfHostServer(configuration);
server.OpenAsync().Wait();
}
public void CleanupHost()
{
if (server != null)
{
server.CloseAsync().Wait();
}
}
}
}

View File

@ -0,0 +1,117 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Net.Http;
using Xunit;
using Xunit.Extensions;
namespace System.Web.Http.ModelBinding
{
/// <summary>
/// End to end functional tests for model binding via query strings
/// </summary>
public class QueryStringBindingTests : ModelBindingTests
{
[Theory]
[InlineData("GetString", "?value=test", "\"test\"")]
[InlineData("GetInt", "?value=99", "99")]
[InlineData("GetBool", "?value=false", "false")]
[InlineData("GetBool", "?value=true", "true")]
[InlineData("GetIntWithDefault", "?value=99", "99")] // action has default, but we provide value
[InlineData("GetIntWithDefault", "", "-1")] // action has default, we provide no value
[InlineData("GetIntFromUri", "?value=99", "99")] // [FromUri]
[InlineData("GetIntPrefixed", "?somePrefix=99", "99")] // [FromUri(Prefix=somePrefix)]
[InlineData("GetIntAsync", "?value=5", "5")]
public void Query_String_Binds_Simple_Types_Get(string action, string queryString, string expectedResponse)
{
// Arrange
HttpRequestMessage request = new HttpRequestMessage()
{
RequestUri = new Uri(baseAddress + String.Format("ModelBinding/{0}{1}", action, queryString)),
Method = HttpMethod.Get
};
// Act
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
string responseString = response.Content.ReadAsStringAsync().Result;
Assert.Equal<string>(expectedResponse, responseString);
}
[Theory]
[InlineData("PostString", "?value=test", "\"test\"")]
[InlineData("PostInt", "?value=99", "99")]
[InlineData("PostBool", "?value=false", "false")]
[InlineData("PostBool", "?value=true", "true")]
[InlineData("PostIntFromUri", "?value=99", "99")] // [FromUri]
[InlineData("PostIntUriPrefixed", "?somePrefix=99", "99")] // [FromUri(Prefix=somePrefix)]
[InlineData("PostIntArray", "?value={[1,2,3]}", "0")] // TODO: DevDiv2 333257 -- make this array real when fix JsonValue array model binding
public void Query_String_Binds_Simple_Types_Post(string action, string queryString, string expectedResponse)
{
// Arrange
HttpRequestMessage request = new HttpRequestMessage()
{
RequestUri = new Uri(baseAddress + String.Format("ModelBinding/{0}{1}", action, queryString)),
Method = HttpMethod.Post
};
// Act
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
string responseString = response.Content.ReadAsStringAsync().Result;
Assert.Equal<string>(expectedResponse, responseString);
}
[Theory]
[InlineData("GetComplexTypeFromUri", "itemName=Tires&quantity=2&customer.Name=Sue", "Tires", 2, "Sue")]
public void Query_String_ComplexType_Type_Get(string action, string queryString, string itemName, int quantity, string customerName)
{
// Arrange
HttpRequestMessage request = new HttpRequestMessage()
{
RequestUri = new Uri(baseAddress + String.Format("ModelBinding/{0}?{1}", action, queryString)),
Method = HttpMethod.Get
};
ModelBindOrder expectedItem = new ModelBindOrder()
{
ItemName = itemName,
Quantity = quantity,
Customer = new ModelBindCustomer { Name = customerName }
};
// Act
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
ModelBindOrder actualItem = response.Content.ReadAsAsync<ModelBindOrder>().Result;
Assert.Equal<ModelBindOrder>(expectedItem, actualItem, new ModelBindOrderEqualityComparer());
}
[Theory]
[InlineData("PostComplexTypeFromUri", "itemName=Tires&quantity=2&customer.Name=Bob", "Tires", 2, "Bob")]
public void Query_String_ComplexType_Type_Post(string action, string queryString, string itemName, int quantity, string customerName)
{
// Arrange
HttpRequestMessage request = new HttpRequestMessage()
{
RequestUri = new Uri(baseAddress + String.Format("ModelBinding/{0}?{1}", action, queryString)),
Method = HttpMethod.Post
};
ModelBindOrder expectedItem = new ModelBindOrder()
{
ItemName = itemName,
Quantity = quantity,
Customer = new ModelBindCustomer { Name = customerName }
};
// Act
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
ModelBindOrder actualItem = response.Content.ReadAsAsync<ModelBindOrder>().Result;
Assert.Equal<ModelBindOrder>(expectedItem, actualItem, new ModelBindOrderEqualityComparer());
}
}
}

View File

@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Net.Http;
using Xunit;
namespace System.Web.Http.ModelBinding
{
/// <summary>
/// End to end functional tests for model binding via routes
/// </summary>
public class RouteBindingTests : ModelBindingTests
{
[Fact]
public void Route_Binds_Simple_Types_Get()
{
// Arrange
HttpRequestMessage request = new HttpRequestMessage()
{
RequestUri = new Uri(baseAddress + "ModelBinding/GetStringFromRoute"),
Method = HttpMethod.Get
};
// Act
HttpResponseMessage response = httpClient.SendAsync(request).Result;
// Assert
string responseString = response.Content.ReadAsStringAsync().Result;
Assert.Equal<string>("\"ModelBinding:GetStringFromRoute\"", responseString);
}
}
}