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
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 14
|
# Visual Studio 14
|
||||||
VisualStudioVersion = 14.0.22822.1
|
VisualStudioVersion = 14.0.22810.0
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|
@ -15,6 +15,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Razor"
|
||||||
EndProject
|
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}"
|
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
|
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}"
|
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
|
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}"
|
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
|
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}"
|
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
|
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}"
|
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
|
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}"
|
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.ActiveCfg = Release|Any CPU
|
||||||
{C48DA9D7-ACB5-4408-AA79-27ECB60A67EF}.Release|Mixed Platforms.Build.0 = 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
|
{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.ActiveCfg = Debug|Any CPU
|
||||||
{F3DF6D0B-16FE-4402-B92C-7243A75CF1FD}.Debug|Any CPU.Build.0 = 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
|
{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|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.ActiveCfg = Release|Any CPU
|
||||||
{1154203C-7579-4525-906E-BC55268421C1}.Release|x86.Build.0 = 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.ActiveCfg = Debug|Any CPU
|
||||||
{A2B72833-5D70-4C42-AE85-E0319926FB8A}.Debug|Any CPU.Build.0 = 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
|
{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}
|
{079EFA1F-0B0A-4853-B27B-5780D111CD85} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||||
{314E9AD6-2FFC-4A92-A8AD-510658C64F1E} = {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}
|
{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}
|
{F3DF6D0B-16FE-4402-B92C-7243A75CF1FD} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||||
{3F6E355E-4869-41D9-943B-D54771221A7F} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
{3F6E355E-4869-41D9-943B-D54771221A7F} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||||
{A8AA326E-8EE8-4F11-B750-23028E0949D7} = {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}
|
{DAB1252D-577C-4912-98BE-1A812BF83F86} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||||
{864FA09D-1E48-403A-A6C8-4F079D2A30F0} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
{864FA09D-1E48-403A-A6C8-4F079D2A30F0} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||||
{1154203C-7579-4525-906E-BC55268421C1} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
{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}
|
{A2B72833-5D70-4C42-AE85-E0319926FB8A} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
|
||||||
{4C2AD8AB-8AC0-46C4-80C6-C5577C7255F6} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
{4C2AD8AB-8AC0-46C4-80C6-C5577C7255F6} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
public string Street { get; set; }
|
public string Street { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact(Skip = "Extra entries in model state #2446.")]
|
||||||
public async Task FromBodyAndRequiredOnProperty_EmptyBody_AddsModelStateError()
|
public async Task FromBodyAndRequiredOnProperty_EmptyBody_AddsModelStateError()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -42,11 +42,18 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
ParameterType = typeof(Person)
|
ParameterType = typeof(Person)
|
||||||
};
|
};
|
||||||
|
|
||||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
|
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
|
||||||
var httpContext = operationContext.HttpContext;
|
request =>
|
||||||
|
{
|
||||||
|
request.Body = new MemoryStream(Encoding.UTF8.GetBytes("{ \"Id\":1234 }"));
|
||||||
|
request.ContentType = "application/json";
|
||||||
|
});
|
||||||
|
|
||||||
ConfigureHttpRequest(httpContext.Request, string.Empty);
|
var actionContext = operationContext
|
||||||
var modelState = new ModelStateDictionary();
|
.HttpContext
|
||||||
|
.RequestServices
|
||||||
|
.GetRequiredService<IScopedInstance<ActionContext>>().Value;
|
||||||
|
var modelState = actionContext.ModelState;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, modelState, operationContext);
|
||||||
|
|
@ -79,10 +86,14 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
ParameterType = typeof(Person)
|
ParameterType = typeof(Person)
|
||||||
};
|
};
|
||||||
|
|
||||||
var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
|
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
|
||||||
var httpContext = operationContext.HttpContext;
|
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();
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -122,9 +133,14 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
ParameterType = typeof(Person4)
|
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;
|
var httpContext = operationContext.HttpContext;
|
||||||
ConfigureHttpRequest(httpContext.Request, string.Empty);
|
|
||||||
var actionContext = httpContext.RequestServices.GetRequiredService<IScopedInstance<ActionContext>>().Value;
|
var actionContext = httpContext.RequestServices.GetRequiredService<IScopedInstance<ActionContext>>().Value;
|
||||||
var modelState = actionContext.ModelState;
|
var modelState = actionContext.ModelState;
|
||||||
|
|
||||||
|
|
@ -177,9 +193,13 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
ParameterType = typeof(Person2)
|
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;
|
var httpContext = operationContext.HttpContext;
|
||||||
ConfigureHttpRequest(httpContext.Request, inputText);
|
|
||||||
var modelState = new ModelStateDictionary();
|
var modelState = new ModelStateDictionary();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|
@ -231,9 +251,13 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
ParameterType = typeof(Person3)
|
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;
|
var httpContext = operationContext.HttpContext;
|
||||||
ConfigureHttpRequest(httpContext.Request, inputText);
|
|
||||||
var actionContext = httpContext.RequestServices.GetRequiredService<IScopedInstance<ActionContext>>().Value;
|
var actionContext = httpContext.RequestServices.GetRequiredService<IScopedInstance<ActionContext>>().Value;
|
||||||
var modelState = actionContext.ModelState;
|
var modelState = actionContext.ModelState;
|
||||||
|
|
||||||
|
|
@ -258,11 +282,5 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
"Required property 'Zip' not found in JSON. Path ''",
|
"Required property 'Zip' not found in JSON. Path ''",
|
||||||
error.Exception.Message);
|
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.
|
// 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.
|
// 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.Http;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||||
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
|
||||||
|
|
@ -11,19 +12,19 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
{
|
{
|
||||||
public static class ModelBindingTestHelper
|
public static class ModelBindingTestHelper
|
||||||
{
|
{
|
||||||
public static OperationBindingContext GetOperationBindingContext()
|
public static OperationBindingContext GetOperationBindingContext(Action<HttpRequest> updateRequest)
|
||||||
{
|
{
|
||||||
var httpContext = ModelBindingTestHelper.GetHttpContext();
|
var httpContext = ModelBindingTestHelper.GetHttpContext(updateRequest);
|
||||||
var actionBindingContextAccessor =
|
var actionBindingContext =
|
||||||
httpContext.RequestServices.GetRequiredService<IScopedInstance<ActionBindingContext>>().Value;
|
httpContext.RequestServices.GetRequiredService<IScopedInstance<ActionBindingContext>>().Value;
|
||||||
return new OperationBindingContext()
|
return new OperationBindingContext()
|
||||||
{
|
{
|
||||||
BodyBindingState = BodyBindingState.NotBodyBased,
|
BodyBindingState = BodyBindingState.NotBodyBased,
|
||||||
HttpContext = httpContext,
|
HttpContext = httpContext,
|
||||||
MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(),
|
MetadataProvider = TestModelMetadataProvider.CreateDefaultProvider(),
|
||||||
ValidatorProvider = actionBindingContextAccessor.ValidatorProvider,
|
ValidatorProvider = actionBindingContext.ValidatorProvider,
|
||||||
ValueProvider = actionBindingContextAccessor.ValueProvider,
|
ValueProvider = actionBindingContext.ValueProvider,
|
||||||
ModelBinder = actionBindingContextAccessor.ModelBinder
|
ModelBinder = actionBindingContext.ModelBinder
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,10 +40,13 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
|
||||||
metadataProvider));
|
metadataProvider));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HttpContext GetHttpContext()
|
public static HttpContext GetHttpContext(Action<HttpRequest> updateRequest)
|
||||||
{
|
{
|
||||||
var options = (new TestMvcOptions()).Options;
|
var options = (new TestMvcOptions()).Options;
|
||||||
var httpContext = new DefaultHttpContext();
|
var httpContext = new DefaultHttpContext();
|
||||||
|
|
||||||
|
updateRequest(httpContext.Request);
|
||||||
|
|
||||||
var serviceCollection = MvcServices.GetDefaultServices();
|
var serviceCollection = MvcServices.GetDefaultServices();
|
||||||
httpContext.RequestServices = serviceCollection.BuildServiceProvider();
|
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