Simple ModelBinders and Simple ModelBinder Poco - 1
Covers simple scenario for each model binder. Covers scenarios mixing a POCO model binder -> Simple Model binder. This contains tests for HeaderModel ServicesModelBinder CancellationTokenModelBinder ByteArrayModelBinder FormFileModelBinder Part 2 Will contain similar tests for FormCollectionModelBinder BinderTypeBasedModelBinder TypeConverterModelBinder TypeMatchModelBinder Any leftovers for BodyModelBinder
This commit is contained in:
parent
30e54609cc
commit
b5b37265e1
30
Mvc.sln
30
Mvc.sln
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.22822.1
|
||||
VisualStudioVersion = 14.0.22810.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
|
||||
EndProject
|
||||
|
|
@ -15,6 +15,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Razor"
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Core", "src\Microsoft.AspNet.Mvc.Core\Microsoft.AspNet.Mvc.Core.xproj", "{C48DA9D7-ACB5-4408-AA79-27ECB60A67EF}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.ModelBinding", "src\Microsoft.AspNet.Mvc.ModelBinding\Microsoft.AspNet.Mvc.ModelBinding.xproj", "{FA915D3D-22C3-4478-97F2-A81D28B6C503}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Common", "src\Microsoft.AspNet.Mvc.Common\Microsoft.AspNet.Mvc.Common.xproj", "{F3DF6D0B-16FE-4402-B92C-7243A75CF1FD}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Razor.Test", "test\Microsoft.AspNet.Mvc.Razor.Test\Microsoft.AspNet.Mvc.Razor.Test.xproj", "{3F6E355E-4869-41D9-943B-D54771221A7F}"
|
||||
|
|
@ -162,8 +164,6 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Integr
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Abstractions", "src\Microsoft.AspNet.Mvc.Abstractions\Microsoft.AspNet.Mvc.Abstractions.xproj", "{1154203C-7579-4525-906E-BC55268421C1}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Abstractions.Test", "test\Microsoft.AspNet.Mvc.Abstractions.Test\Microsoft.AspNet.Mvc.Abstractions.Test.xproj", "{DA000953-7532-4DF5-8DB9-8143DF98D999}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.ApiExplorer", "src\Microsoft.AspNet.Mvc.ApiExplorer\Microsoft.AspNet.Mvc.ApiExplorer.xproj", "{A2B72833-5D70-4C42-AE85-E0319926FB8A}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.ApiExplorer.Test", "test\Microsoft.AspNet.Mvc.ApiExplorer.Test\Microsoft.AspNet.Mvc.ApiExplorer.Test.xproj", "{4C2AD8AB-8AC0-46C4-80C6-C5577C7255F6}"
|
||||
|
|
@ -208,6 +208,16 @@ Global
|
|||
{C48DA9D7-ACB5-4408-AA79-27ECB60A67EF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{C48DA9D7-ACB5-4408-AA79-27ECB60A67EF}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{C48DA9D7-ACB5-4408-AA79-27ECB60A67EF}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{FA915D3D-22C3-4478-97F2-A81D28B6C503}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FA915D3D-22C3-4478-97F2-A81D28B6C503}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FA915D3D-22C3-4478-97F2-A81D28B6C503}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{FA915D3D-22C3-4478-97F2-A81D28B6C503}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{FA915D3D-22C3-4478-97F2-A81D28B6C503}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{FA915D3D-22C3-4478-97F2-A81D28B6C503}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FA915D3D-22C3-4478-97F2-A81D28B6C503}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FA915D3D-22C3-4478-97F2-A81D28B6C503}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{FA915D3D-22C3-4478-97F2-A81D28B6C503}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{FA915D3D-22C3-4478-97F2-A81D28B6C503}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F3DF6D0B-16FE-4402-B92C-7243A75CF1FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F3DF6D0B-16FE-4402-B92C-7243A75CF1FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F3DF6D0B-16FE-4402-B92C-7243A75CF1FD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
|
|
@ -974,18 +984,6 @@ Global
|
|||
{1154203C-7579-4525-906E-BC55268421C1}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{1154203C-7579-4525-906E-BC55268421C1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{1154203C-7579-4525-906E-BC55268421C1}.Release|x86.Build.0 = Release|Any CPU
|
||||
{DA000953-7532-4DF5-8DB9-8143DF98D999}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DA000953-7532-4DF5-8DB9-8143DF98D999}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DA000953-7532-4DF5-8DB9-8143DF98D999}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{DA000953-7532-4DF5-8DB9-8143DF98D999}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{DA000953-7532-4DF5-8DB9-8143DF98D999}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{DA000953-7532-4DF5-8DB9-8143DF98D999}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{DA000953-7532-4DF5-8DB9-8143DF98D999}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DA000953-7532-4DF5-8DB9-8143DF98D999}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DA000953-7532-4DF5-8DB9-8143DF98D999}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{DA000953-7532-4DF5-8DB9-8143DF98D999}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{DA000953-7532-4DF5-8DB9-8143DF98D999}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{DA000953-7532-4DF5-8DB9-8143DF98D999}.Release|x86.Build.0 = Release|Any CPU
|
||||
{A2B72833-5D70-4C42-AE85-E0319926FB8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A2B72833-5D70-4C42-AE85-E0319926FB8A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A2B72833-5D70-4C42-AE85-E0319926FB8A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
|
|
@ -1018,6 +1016,7 @@ Global
|
|||
{079EFA1F-0B0A-4853-B27B-5780D111CD85} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{314E9AD6-2FFC-4A92-A8AD-510658C64F1E} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{C48DA9D7-ACB5-4408-AA79-27ECB60A67EF} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{FA915D3D-22C3-4478-97F2-A81D28B6C503} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{F3DF6D0B-16FE-4402-B92C-7243A75CF1FD} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{3F6E355E-4869-41D9-943B-D54771221A7F} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||
{A8AA326E-8EE8-4F11-B750-23028E0949D7} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||
|
|
@ -1089,7 +1088,6 @@ Global
|
|||
{DAB1252D-577C-4912-98BE-1A812BF83F86} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{864FA09D-1E48-403A-A6C8-4F079D2A30F0} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||
{1154203C-7579-4525-906E-BC55268421C1} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{DA000953-7532-4DF5-8DB9-8143DF98D999} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||
{A2B72833-5D70-4C42-AE85-E0319926FB8A} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||
{4C2AD8AB-8AC0-46C4-80C6-C5577C7255F6} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||
EndGlobalSection
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
|||
public string Street { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Fact(Skip = "Extra entries in model state #2446.")]
|
||||
public async Task FromBodyAndRequiredOnProperty_EmptyBody_AddsModelStateError()
|
||||
{
|
||||
// Arrange
|
||||
|
|
@ -42,11 +42,18 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
|||
ParameterType = typeof(Person)
|
||||
};
|
||||
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
|
||||
var httpContext = operationContext.HttpContext;
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
|
||||
request =>
|
||||
{
|
||||
request.Body = new MemoryStream(Encoding.UTF8.GetBytes("{ \"Id\":1234 }"));
|
||||
request.ContentType = "application/json";
|
||||
});
|
||||
|
||||
ConfigureHttpRequest(httpContext.Request, string.Empty);
|
||||
var modelState = new ModelStateDictionary();
|
||||
var actionContext = operationContext
|
||||
.HttpContext
|
||||
.RequestServices
|
||||
.GetRequiredService<IScopedInstance<ActionContext>>().Value;
|
||||
var modelState = actionContext.ModelState;
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
|
@ -79,10 +86,14 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
|||
ParameterType = typeof(Person)
|
||||
};
|
||||
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
|
||||
var httpContext = operationContext.HttpContext;
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
|
||||
request =>
|
||||
{
|
||||
request.Body = new MemoryStream(Encoding.UTF8.GetBytes("{ \"Id\":1234 }"));
|
||||
request.ContentType = "application/json";
|
||||
});
|
||||
|
||||
ConfigureHttpRequest(httpContext.Request, "{ \"Id\":1234 }");
|
||||
var httpContext = operationContext.HttpContext;
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
|
|
@ -122,9 +133,14 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
|||
ParameterType = typeof(Person4)
|
||||
};
|
||||
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
|
||||
request =>
|
||||
{
|
||||
request.Body = new MemoryStream(Encoding.UTF8.GetBytes(string.Empty));
|
||||
request.ContentType = "application/json";
|
||||
});
|
||||
|
||||
var httpContext = operationContext.HttpContext;
|
||||
ConfigureHttpRequest(httpContext.Request, string.Empty);
|
||||
var actionContext = httpContext.RequestServices.GetRequiredService<IScopedInstance<ActionContext>>().Value;
|
||||
var modelState = actionContext.ModelState;
|
||||
|
||||
|
|
@ -177,9 +193,13 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
|||
ParameterType = typeof(Person2)
|
||||
};
|
||||
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
|
||||
request =>
|
||||
{
|
||||
request.Body = new MemoryStream(Encoding.UTF8.GetBytes(inputText));
|
||||
request.ContentType = "application/json";
|
||||
});
|
||||
var httpContext = operationContext.HttpContext;
|
||||
ConfigureHttpRequest(httpContext.Request, inputText);
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
|
|
@ -231,9 +251,13 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
|||
ParameterType = typeof(Person3)
|
||||
};
|
||||
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
|
||||
request =>
|
||||
{
|
||||
request.Body = new MemoryStream(Encoding.UTF8.GetBytes(inputText));
|
||||
request.ContentType = "application/json";
|
||||
});
|
||||
var httpContext = operationContext.HttpContext;
|
||||
ConfigureHttpRequest(httpContext.Request, inputText);
|
||||
var actionContext = httpContext.RequestServices.GetRequiredService<IScopedInstance<ActionContext>>().Value;
|
||||
var modelState = actionContext.ModelState;
|
||||
|
||||
|
|
@ -258,11 +282,5 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
|||
"Required property 'Zip' not found in JSON. Path ''",
|
||||
error.Exception.Message);
|
||||
}
|
||||
|
||||
private static void ConfigureHttpRequest(HttpRequest request, string jsonContent)
|
||||
{
|
||||
request.Body = new MemoryStream(Encoding.UTF8.GetBytes(jsonContent));
|
||||
request.ContentType = "application/json";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||
{
|
||||
public class ByteArrayModelBinderIntegrationTest
|
||||
{
|
||||
private class Person
|
||||
{
|
||||
public byte[] Token { get; set; }
|
||||
}
|
||||
|
||||
[Theory(Skip = "Extra entries in model state #2446, ModelState.Value not set due to #2445, #2447")]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task BindProperty_WithData_GetsBound(bool fallBackScenario)
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "Parameter1",
|
||||
BindingInfo = new BindingInfo(),
|
||||
ParameterType = typeof(Person)
|
||||
};
|
||||
|
||||
var prefix = fallBackScenario ? string.Empty : "Parameter1";
|
||||
var queryStringKey = fallBackScenario ? "Token" : prefix + "." + "Token";
|
||||
|
||||
// any valid base64 string
|
||||
var expectedValue = new byte[] { 12, 13 };
|
||||
var value = Convert.ToBase64String(expectedValue);
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
|
||||
request =>
|
||||
{
|
||||
request.QueryString = new QueryString(queryStringKey, value);
|
||||
});
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
|
||||
// ModelBindingResult
|
||||
Assert.NotNull(modelBindingResult);
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
// Model
|
||||
var boundPerson = Assert.IsType<Person>(modelBindingResult.Model);
|
||||
Assert.NotNull(boundPerson);
|
||||
Assert.NotNull(boundPerson.Token);
|
||||
Assert.Equal(expectedValue, boundPerson.Token);
|
||||
|
||||
// ModelState
|
||||
Assert.True(modelState.IsValid);
|
||||
|
||||
Assert.Equal(2, modelState.Keys.Count); // Should be only two keys. bug #2446
|
||||
Assert.Single(modelState.Keys, k => k == prefix);
|
||||
Assert.Single(modelState.Keys, k => k == queryStringKey);
|
||||
|
||||
var key = Assert.Single(modelState.Keys, k => k == queryStringKey + "[0]");
|
||||
Assert.NotNull(modelState[key].Value); // should be non null bug #2445.
|
||||
Assert.Empty(modelState[key].Errors);
|
||||
Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); // Should be skipped. bug#2447
|
||||
|
||||
key = Assert.Single(modelState.Keys, k => k == queryStringKey + "[1]");
|
||||
Assert.NotNull(modelState[key].Value); // should be non null bug #2445.
|
||||
Assert.Empty(modelState[key].Errors);
|
||||
Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState); // Should be skipped. bug#2447
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BindParameter_NoData_DoesNotGetBound()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "Parameter1",
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BinderModelName = "CustomParameter",
|
||||
},
|
||||
|
||||
ParameterType = typeof(byte[])
|
||||
};
|
||||
|
||||
// No data is passed.
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(httpContext => { });
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
|
||||
// ModelBindingResult
|
||||
Assert.Null(modelBindingResult);
|
||||
|
||||
// ModelState
|
||||
Assert.True(modelState.IsValid);
|
||||
Assert.Empty(modelState.Keys);
|
||||
}
|
||||
|
||||
[Fact(Skip = "ModelState.Value not set due to #2445, #2446")]
|
||||
public async Task BindParameter_WithData_GetsBound()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "Parameter1",
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BinderModelName = "CustomParameter",
|
||||
},
|
||||
|
||||
ParameterType = typeof(byte[])
|
||||
};
|
||||
|
||||
// any valid base64 string
|
||||
var value = "four";
|
||||
var expectedValue = Convert.FromBase64String(value);
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
|
||||
request =>
|
||||
{
|
||||
request.QueryString = new QueryString("CustomParameter", value);
|
||||
});
|
||||
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
|
||||
// ModelBindingResult
|
||||
Assert.NotNull(modelBindingResult);
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
var model = Assert.IsType<byte[]>(modelBindingResult.Model);
|
||||
|
||||
// Model
|
||||
Assert.Equal(expectedValue, model);
|
||||
|
||||
// ModelState
|
||||
Assert.True(modelState.IsValid);
|
||||
|
||||
Assert.Equal(3, modelState.Count);
|
||||
Assert.Single(modelState.Keys, k => k == "CustomParameter[0]");
|
||||
Assert.Single(modelState.Keys, k => k == "CustomParameter[1]");
|
||||
var key = Assert.Single(modelState.Keys, k => k == "CustomParameter[2]");
|
||||
|
||||
Assert.NotNull(modelState[key].Value);
|
||||
Assert.Equal(value, modelState[key].Value.AttemptedValue);
|
||||
Assert.Equal(expectedValue, modelState[key].Value.RawValue);
|
||||
Assert.Empty(modelState[key].Errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,152 @@
|
|||
// 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.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||
{
|
||||
public class CancellationTokenModelBinderIntegrationTest
|
||||
{
|
||||
private class Person
|
||||
{
|
||||
public CancellationToken Token { get; set; }
|
||||
}
|
||||
|
||||
[Fact(Skip = "CancellationToken should not be validated #2447.")]
|
||||
public async Task BindProperty_WithData__WithPrefix_GetsBound()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "Parameter1",
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BinderModelName = "CustomParameter",
|
||||
},
|
||||
|
||||
ParameterType = typeof(Person)
|
||||
};
|
||||
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(httpContext => { });
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
|
||||
// ModelBindingResult
|
||||
Assert.NotNull(modelBindingResult);
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
// Model
|
||||
var boundPerson = Assert.IsType<Person>(modelBindingResult.Model);
|
||||
Assert.NotNull(boundPerson);
|
||||
Assert.NotNull(boundPerson.Token);
|
||||
|
||||
// ModelState
|
||||
Assert.True(modelState.IsValid);
|
||||
|
||||
Assert.Equal(2, modelState.Keys.Count);
|
||||
Assert.Single(modelState.Keys, k => k == "CustomParameter");
|
||||
|
||||
var key = Assert.Single(modelState.Keys, k => k == "CustomParameter.Token");
|
||||
Assert.Null(modelState[key].Value);
|
||||
Assert.Empty(modelState[key].Errors);
|
||||
|
||||
// This Assert Fails.
|
||||
Assert.Equal(ModelValidationState.Skipped, modelState[key].ValidationState);
|
||||
}
|
||||
|
||||
[Fact(Skip = "CancellationToken should not be validated #2447,Extra entries in model state dictionary. #2466")]
|
||||
public async Task BindProperty_WithData__WithEmptyPrefix_GetsBound()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "Parameter1",
|
||||
BindingInfo = new BindingInfo(),
|
||||
ParameterType = typeof(Person)
|
||||
};
|
||||
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(httpContext => { });
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
|
||||
// ModelBindingResult
|
||||
Assert.NotNull(modelBindingResult);
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
// Model
|
||||
var boundPerson = Assert.IsType<Person>(modelBindingResult.Model);
|
||||
Assert.NotNull(boundPerson);
|
||||
Assert.NotNull(boundPerson.Token);
|
||||
|
||||
// ModelState
|
||||
Assert.True(modelState.IsValid);
|
||||
var key = Assert.Single(modelState.Keys);
|
||||
Assert.Equal("Token", key);
|
||||
Assert.Null(modelState[key].Value);
|
||||
Assert.Empty(modelState[key].Errors);
|
||||
|
||||
// This Assert Fails.
|
||||
Assert.Equal(ModelValidationState.Skipped, modelState[key].ValidationState);
|
||||
}
|
||||
|
||||
[Fact(Skip = "CancellationToken should not be validated #2447.")]
|
||||
public async Task BindParameter_WithData_GetsBound()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "Parameter1",
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BinderModelName = "CustomParameter",
|
||||
},
|
||||
|
||||
ParameterType = typeof(CancellationToken)
|
||||
};
|
||||
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(httpContext => { });
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
|
||||
// ModelBindingResult
|
||||
Assert.NotNull(modelBindingResult);
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
// Model
|
||||
var token = Assert.IsType<CancellationToken>(modelBindingResult.Model);
|
||||
Assert.NotNull(token);
|
||||
|
||||
// ModelState
|
||||
Assert.True(modelState.IsValid);
|
||||
var key = Assert.Single(modelState.Keys);
|
||||
Assert.Equal("CustomParameter", key);
|
||||
Assert.Null(modelState[key].Value);
|
||||
Assert.Empty(modelState[key].Errors);
|
||||
|
||||
// This assert fails.
|
||||
Assert.Equal(ModelValidationState.Skipped, modelState[key].ValidationState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
// 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.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Collections;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||
{
|
||||
public class FormFileModelBindingIntegrationTest
|
||||
{
|
||||
private class Person
|
||||
{
|
||||
public Address Address { get; set; }
|
||||
}
|
||||
|
||||
private class Address
|
||||
{
|
||||
public int Zip { get; set; }
|
||||
|
||||
public IFormFile File { get; set; }
|
||||
}
|
||||
|
||||
[Fact(Skip = "ModelState.Value not set due to #2445, Extra entries in model state #2446.")]
|
||||
public async Task BindProperty_WithData_WithEmptyPrefix_GetsBound()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "Parameter1",
|
||||
BindingInfo = new BindingInfo(),
|
||||
ParameterType = typeof(Person)
|
||||
};
|
||||
|
||||
var data = "Some Data Is Better Than No Data.";
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
|
||||
request =>
|
||||
{
|
||||
request.QueryString = new QueryString("Address.Zip", "12345");
|
||||
UpdateRequest(request, data, "Address.File");
|
||||
});
|
||||
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
|
||||
// ModelBindingResult
|
||||
Assert.NotNull(modelBindingResult);
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
// Model
|
||||
var boundPerson = Assert.IsType<Person>(modelBindingResult.Model);
|
||||
Assert.NotNull(boundPerson.Address);
|
||||
var file = Assert.IsAssignableFrom<IFormFile>(boundPerson.Address.File);
|
||||
Assert.Equal("form-data; name=Address.File; filename=text.txt", file.ContentDisposition);
|
||||
var reader = new StreamReader(boundPerson.Address.File.OpenReadStream());
|
||||
Assert.Equal(data, reader.ReadToEnd());
|
||||
|
||||
// ModelState
|
||||
Assert.True(modelState.IsValid);
|
||||
Assert.Equal(2, modelState.Count);
|
||||
Assert.Single(modelState.Keys, k => k == "Address.Zip");
|
||||
var key = Assert.Single(modelState.Keys, k => k == "Address.File"); // Should be only one key. bug #2446
|
||||
Assert.NotNull(modelState[key].Value); // should be non null bug #2445.
|
||||
Assert.Empty(modelState[key].Errors);
|
||||
Assert.Equal(ModelValidationState.Valid, modelState[key].ValidationState);
|
||||
}
|
||||
|
||||
[Fact(Skip = "Extra entries in model state #2446.")]
|
||||
public async Task BindParameter_WithData_GetsBound()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "Parameter1",
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
// Setting a custom parameter prevents it from falling back to an empty prefix.
|
||||
BinderModelName = "CustomParameter",
|
||||
},
|
||||
|
||||
ParameterType = typeof(IFormFile)
|
||||
};
|
||||
|
||||
var data = "Some Data Is Better Than No Data.";
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
|
||||
request =>
|
||||
{
|
||||
UpdateRequest(request, data, "CustomParameter");
|
||||
});
|
||||
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
// ModelBindingResult
|
||||
Assert.NotNull(modelBindingResult);
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
// Model
|
||||
var file = Assert.IsType<FormFile>(modelBindingResult.Model);
|
||||
Assert.NotNull(file);
|
||||
Assert.Equal("form-data; name=CustomParameter; filename=text.txt", file.ContentDisposition);
|
||||
var reader = new StreamReader(file.OpenReadStream());
|
||||
Assert.Equal(data, reader.ReadToEnd());
|
||||
|
||||
// ModelState
|
||||
Assert.True(modelState.IsValid);
|
||||
|
||||
// Validation should be skipped because we do not validate any parameters and since IFormFile is not
|
||||
// IValidatableObject, we should have no entries in the model state dictionary.
|
||||
Assert.Empty(modelState.Keys); // Enable when we fix #2446.
|
||||
}
|
||||
|
||||
[Fact(Skip = "Extra entries in model state #2446.")]
|
||||
public async Task BindParameter_NoData_DoesNotGetBound()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "Parameter1",
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BinderModelName = "CustomParameter",
|
||||
},
|
||||
|
||||
ParameterType = typeof(IFormFile)
|
||||
};
|
||||
|
||||
// No data is passed.
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request =>
|
||||
{
|
||||
request.ContentType = "multipart/form-data";
|
||||
});
|
||||
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
|
||||
// ModelBindingResult
|
||||
Assert.NotNull(modelBindingResult); // Fails due to bug #2456
|
||||
Assert.Null(modelBindingResult.Model);
|
||||
|
||||
// ModelState
|
||||
Assert.True(modelState.IsValid);
|
||||
Assert.Empty(modelState.Keys);
|
||||
}
|
||||
|
||||
private void UpdateRequest(HttpRequest request, string data, string name)
|
||||
{
|
||||
var fileCollection = new FormFileCollection();
|
||||
var formCollection = new FormCollection(new Dictionary<string, string[]>(), fileCollection);
|
||||
var memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(data));
|
||||
|
||||
request.Form = formCollection;
|
||||
request.ContentType = "multipart/form-data";
|
||||
request.Headers["Content-Disposition"] = "form-data; name=" + name + "; filename=text.txt";
|
||||
fileCollection.Add(new FormFile(memoryStream, 0, data.Length)
|
||||
{
|
||||
Headers = request.Headers
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
// 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.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||
{
|
||||
public class HeaderModelBinderIntegrationTest
|
||||
{
|
||||
private class Person
|
||||
{
|
||||
public Address Address { get; set; }
|
||||
}
|
||||
|
||||
private class Address
|
||||
{
|
||||
[FromHeader(Name = "Header")]
|
||||
[Required]
|
||||
public string Street { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BindPropertyFromHeader_NoData_UsesFullPathAsKeyForModelStateErrors()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "Parameter1",
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BinderModelName = "CustomParameter",
|
||||
},
|
||||
ParameterType = typeof(Person)
|
||||
};
|
||||
|
||||
// Do not add any headers.
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => { });
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
|
||||
// ModelBindingResult
|
||||
Assert.NotNull(modelBindingResult);
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
// Model
|
||||
var boundPerson = Assert.IsType<Person>(modelBindingResult.Model);
|
||||
Assert.NotNull(boundPerson);
|
||||
|
||||
// ModelState
|
||||
Assert.False(modelState.IsValid);
|
||||
var key = Assert.Single(modelState.Keys);
|
||||
Assert.Equal("CustomParameter.Address.Header", key);
|
||||
var error = Assert.Single(modelState[key].Errors);
|
||||
Assert.Equal("The Street field is required.", error.ErrorMessage);
|
||||
}
|
||||
|
||||
[Fact(Skip = "ModelState.Value not set due to #2445")]
|
||||
public async Task BindPropertyFromHeader_WithPrefix_GetsBound()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "Parameter1",
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BinderModelName = "prefix",
|
||||
},
|
||||
ParameterType = typeof(Person)
|
||||
};
|
||||
|
||||
// Do not add any headers.
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => {
|
||||
request.Headers.Add("Header", new[] { "someValue" });
|
||||
});
|
||||
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
|
||||
// ModelBindingResult
|
||||
Assert.NotNull(modelBindingResult);
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
// Model
|
||||
var boundPerson = Assert.IsType<Person>(modelBindingResult.Model);
|
||||
Assert.NotNull(boundPerson);
|
||||
Assert.NotNull(boundPerson.Address);
|
||||
Assert.Equal("someValue", boundPerson.Address.Street);
|
||||
|
||||
// ModelState
|
||||
Assert.True(modelState.IsValid);
|
||||
Assert.Equal(3, modelState.Count);
|
||||
Assert.Single(modelState.Keys, k => k == "prefix.Address");
|
||||
Assert.Single(modelState.Keys, k => k == "prefix");
|
||||
|
||||
var key = Assert.Single(modelState.Keys, k => k == "prefix.Address.Header");
|
||||
Assert.NotNull(modelState[key].Value);
|
||||
Assert.Equal("someValue", modelState[key].Value.RawValue);
|
||||
Assert.Equal("someValue", modelState[key].Value.AttemptedValue);
|
||||
}
|
||||
|
||||
// The scenario is interesting as we to bind the top level model we fallback to empty prefix,
|
||||
// and hence the model state keys have an empty prefix.
|
||||
[Fact(Skip = "ModelState.Value not set due to #2445. ModelState should not have empty key #2466.")]
|
||||
public async Task BindPropertyFromHeader_WithData_WithEmptyPrefix_GetsBound()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "Parameter1",
|
||||
BindingInfo = new BindingInfo(),
|
||||
ParameterType = typeof(Person)
|
||||
};
|
||||
|
||||
// Do not add any headers.
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(request => {
|
||||
request.Headers.Add("Header", new[] { "someValue" });
|
||||
});
|
||||
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
|
||||
// ModelBindingResult
|
||||
Assert.NotNull(modelBindingResult);
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
// Model
|
||||
var boundPerson = Assert.IsType<Person>(modelBindingResult.Model);
|
||||
Assert.NotNull(boundPerson);
|
||||
Assert.NotNull(boundPerson.Address);
|
||||
Assert.Equal("someValue", boundPerson.Address.Street);
|
||||
|
||||
// ModelState
|
||||
Assert.True(modelState.IsValid);
|
||||
Assert.Equal(2, modelState.Count);
|
||||
Assert.Single(modelState.Keys, k => k == "Address");
|
||||
var key = Assert.Single(modelState.Keys, k => k == "Address.Header");
|
||||
Assert.NotNull(modelState[key].Value);
|
||||
Assert.Equal("someValue", modelState[key].Value.RawValue);
|
||||
Assert.Equal("someValue", modelState[key].Value.AttemptedValue);
|
||||
}
|
||||
|
||||
[Theory(Skip = "Extra entries in model state #2446.")]
|
||||
[InlineData(typeof(string[]), "value1, value2, value3")]
|
||||
[InlineData(typeof(string), "value")]
|
||||
public async Task BindParameterFromHeader_WithData_WithPrefix_ModelGetsBound(Type modelType, string value)
|
||||
{
|
||||
// Arrange
|
||||
var expectedValue = value.Split(',').Select(v => v.Trim());
|
||||
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "Parameter1",
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BinderModelName = "CustomParameter",
|
||||
BindingSource = BindingSource.Header
|
||||
},
|
||||
ParameterType = modelType
|
||||
};
|
||||
|
||||
Action<HttpRequest> action = (r) => r.Headers.Add("CustomParameter", new[] { value });
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(action);
|
||||
|
||||
// Do not add any headers.
|
||||
var httpContext = operationContext.HttpContext;
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
|
||||
// ModelBindingResult
|
||||
Assert.NotNull(modelBindingResult);
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
// Model
|
||||
Assert.NotNull(modelBindingResult.Model);
|
||||
Assert.IsType(modelType, modelBindingResult.Model);
|
||||
|
||||
// ModelState
|
||||
Assert.True(modelState.IsValid);
|
||||
var key = Assert.Single(modelState.Keys);
|
||||
Assert.Equal("CustomParameter", key);
|
||||
|
||||
Assert.NotNull(modelState[key].Value);
|
||||
Assert.Equal(expectedValue, modelState[key].Value.RawValue);
|
||||
Assert.Equal(value, modelState[key].Value.AttemptedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
// 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 Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||
|
|
@ -11,19 +12,19 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
|||
{
|
||||
public static class ModelBindingTestHelper
|
||||
{
|
||||
public static OperationBindingContext GetOperationBindingContext()
|
||||
public static OperationBindingContext GetOperationBindingContext(Action<HttpRequest> updateRequest)
|
||||
{
|
||||
var httpContext = ModelBindingTestHelper.GetHttpContext();
|
||||
var actionBindingContextAccessor =
|
||||
var httpContext = ModelBindingTestHelper.GetHttpContext(updateRequest);
|
||||
var actionBindingContext =
|
||||
httpContext.RequestServices.GetRequiredService<IScopedInstance<ActionBindingContext>>().Value;
|
||||
return new OperationBindingContext()
|
||||
{
|
||||
BodyBindingState = BodyBindingState.NotBodyBased,
|
||||
HttpContext = httpContext,
|
||||
MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(),
|
||||
ValidatorProvider = actionBindingContextAccessor.ValidatorProvider,
|
||||
ValueProvider = actionBindingContextAccessor.ValueProvider,
|
||||
ModelBinder = actionBindingContextAccessor.ModelBinder
|
||||
ValidatorProvider = actionBindingContext.ValidatorProvider,
|
||||
ValueProvider = actionBindingContext.ValueProvider,
|
||||
ModelBinder = actionBindingContext.ModelBinder
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -39,10 +40,13 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
|||
metadataProvider));
|
||||
}
|
||||
|
||||
public static HttpContext GetHttpContext()
|
||||
public static HttpContext GetHttpContext(Action<HttpRequest> updateRequest)
|
||||
{
|
||||
var options = (new TestMvcOptions()).Options;
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
updateRequest(httpContext.Request);
|
||||
|
||||
var serviceCollection = MvcServices.GetDefaultServices();
|
||||
httpContext.RequestServices = serviceCollection.BuildServiceProvider();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,152 @@
|
|||
// 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.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||
{
|
||||
public class ServicesModelBinderIntegrationTest
|
||||
{
|
||||
private class Person
|
||||
{
|
||||
public Address Address { get; set; }
|
||||
}
|
||||
|
||||
private class Address
|
||||
{
|
||||
// Using a service type already in defaults.
|
||||
[FromServices]
|
||||
public JsonOutputFormatter OutputFormatter { get; set; }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BindPropertyFromService_WithData_WithPrefix_GetsBound()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "Parameter1",
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BinderModelName = "CustomParameter",
|
||||
},
|
||||
|
||||
ParameterType = typeof(Person)
|
||||
};
|
||||
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(httpContext => { });
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
|
||||
// ModelBindingResult
|
||||
Assert.NotNull(modelBindingResult);
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
// Model
|
||||
var boundPerson = Assert.IsType<Person>(modelBindingResult.Model);
|
||||
Assert.NotNull(boundPerson);
|
||||
Assert.NotNull(boundPerson.Address.OutputFormatter);
|
||||
|
||||
// ModelState
|
||||
Assert.True(modelState.IsValid);
|
||||
|
||||
Assert.Equal(3, modelState.Keys.Count);
|
||||
Assert.Single(modelState.Keys, k => k == "CustomParameter");
|
||||
Assert.Single(modelState.Keys, k => k == "CustomParameter.Address");
|
||||
|
||||
var key = Assert.Single(modelState.Keys, k => k == "CustomParameter.Address.OutputFormatter");
|
||||
Assert.Equal(ModelValidationState.Skipped, modelState[key].ValidationState);
|
||||
Assert.Null(modelState[key].Value);
|
||||
Assert.Empty(modelState[key].Errors);
|
||||
}
|
||||
|
||||
[Fact(Skip = "ModelState should not have empty key #2466.")]
|
||||
public async Task BindPropertyFromService_WithData_WithEmptyPrefix_GetsBound()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "Parameter1",
|
||||
BindingInfo = new BindingInfo(),
|
||||
ParameterType = typeof(Person)
|
||||
};
|
||||
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(httpContext => { });
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
|
||||
// ModelBindingResult
|
||||
Assert.NotNull(modelBindingResult);
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
// Model
|
||||
var boundPerson = Assert.IsType<Person>(modelBindingResult.Model);
|
||||
Assert.NotNull(boundPerson);
|
||||
Assert.NotNull(boundPerson.Address.OutputFormatter);
|
||||
|
||||
// ModelState
|
||||
Assert.True(modelState.IsValid);
|
||||
Assert.Equal(2, modelState.Keys.Count);
|
||||
Assert.Single(modelState.Keys, k => k == "Address");
|
||||
var key = Assert.Single(modelState.Keys, k => k == "Address.OutputFormatter");
|
||||
Assert.Equal(ModelValidationState.Skipped, modelState[key].ValidationState);
|
||||
Assert.Null(modelState[key].Value); // For non user bound models there should be no value.
|
||||
Assert.Empty(modelState[key].Errors);
|
||||
}
|
||||
|
||||
[Fact(Skip = "#2464 ModelState should not have entry for non request bound models.")]
|
||||
public async Task BindParameterFromService_WithData_GetsBound()
|
||||
{
|
||||
// Arrange
|
||||
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
|
||||
var parameter = new ParameterDescriptor()
|
||||
{
|
||||
Name = "Parameter1",
|
||||
BindingInfo = new BindingInfo()
|
||||
{
|
||||
BinderModelName = "CustomParameter",
|
||||
BindingSource = BindingSource.Services
|
||||
},
|
||||
|
||||
// Using a service type already in defaults.
|
||||
ParameterType = typeof(JsonOutputFormatter)
|
||||
};
|
||||
|
||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(httpContext => { });
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
// Act
|
||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||
|
||||
// Assert
|
||||
|
||||
// ModelBindingResult
|
||||
Assert.NotNull(modelBindingResult);
|
||||
Assert.True(modelBindingResult.IsModelSet);
|
||||
|
||||
// Model
|
||||
var outputFormatter = Assert.IsType<JsonOutputFormatter>(modelBindingResult.Model);
|
||||
Assert.NotNull(outputFormatter);
|
||||
|
||||
// ModelState
|
||||
Assert.True(modelState.IsValid);
|
||||
Assert.Empty(modelState.Keys);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue