Skip to content

Commit 280cc96

Browse files
authored
Capture parsing errors in model state when binding convertible keys (#50929)
1 parent 2335aa5 commit 280cc96

File tree

2 files changed

+84
-1
lines changed

2 files changed

+84
-1
lines changed

src/Mvc/Mvc.Core/src/ModelBinding/Binders/DictionaryModelBinder.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,17 @@ public override async Task BindModelAsync(ModelBindingContext bindingContext)
163163
{
164164
// Use InvariantCulture to convert the key since ExpressionHelper.GetExpressionText() would use
165165
// that culture when rendering a form.
166-
var convertedKey = ModelBindingHelper.ConvertTo<TKey>(kvp.Key, culture: null);
166+
TKey? convertedKey;
167+
try
168+
{
169+
convertedKey = ModelBindingHelper.ConvertTo<TKey>(kvp.Key, culture: null);
170+
}
171+
catch (Exception ex)
172+
{
173+
bindingContext.Result = ModelBindingResult.Failed();
174+
bindingContext.ModelState.AddModelError(bindingContext.ModelName, ex.Message);
175+
return;
176+
}
167177

168178
using (bindingContext.EnterNestedScope(
169179
modelMetadata: valueMetadata,

src/Mvc/test/Mvc.IntegrationTests/DictionaryModelBinderIntegrationTest.cs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,6 +1352,79 @@ public async Task DictionaryModelBinder_ValuesIsNonNullableType_AppliesImplicitR
13521352
Assert.False(modelState.IsValid);
13531353
}
13541354

1355+
[Fact]
1356+
public async Task DictionaryModelBinder_BindsDictionaryOfSimpleValueAndEnumKey_WithError()
1357+
{
1358+
// Arrange
1359+
var expectedDictionary = new Dictionary<DayOfWeek, string>
1360+
{
1361+
{ DayOfWeek.Monday, "hello" },
1362+
{ DayOfWeek.Tuesday, "world" },
1363+
};
1364+
var parameterBinder = ModelBindingTestHelper.GetParameterBinder();
1365+
var parameter = new ParameterDescriptor()
1366+
{
1367+
Name = "parameter",
1368+
ParameterType = typeof(Dictionary<DayOfWeek, string>)
1369+
};
1370+
1371+
var testContext = ModelBindingTestHelper.GetTestContext(request =>
1372+
{
1373+
request.QueryString = new QueryString("?parameter[Monday]=hello&parameter[Tuesday]=world&parameter[Invalid]=exclamation");
1374+
});
1375+
1376+
var modelState = testContext.ModelState;
1377+
1378+
// Act
1379+
var modelBindingResult = await parameterBinder.BindModelAsync(parameter, testContext);
1380+
1381+
// Assert
1382+
Assert.False(modelBindingResult.IsModelSet);
1383+
1384+
Assert.NotEmpty(modelState);
1385+
Assert.Equal(1, modelState.ErrorCount);
1386+
Assert.False(modelState.IsValid);
1387+
Assert.Equal("Invalid is not a valid value for DayOfWeek.", modelState["parameter"].Errors[0].ErrorMessage);
1388+
}
1389+
1390+
[Fact]
1391+
public async Task DictionaryModelBinder_BindsDictionaryOfSimpleValueAndEnumValue_WithError()
1392+
{
1393+
// Arrange
1394+
var expectedDictionary = new Dictionary<string, DayOfWeek>
1395+
{
1396+
{ "hello", DayOfWeek.Monday },
1397+
{ "world", DayOfWeek.Tuesday },
1398+
{ "exclamation", DayOfWeek.Sunday },
1399+
};
1400+
var parameterBinder = ModelBindingTestHelper.GetParameterBinder();
1401+
var parameter = new ParameterDescriptor()
1402+
{
1403+
Name = "parameter",
1404+
ParameterType = typeof(Dictionary<string, DayOfWeek>)
1405+
};
1406+
1407+
var testContext = ModelBindingTestHelper.GetTestContext(request =>
1408+
{
1409+
request.QueryString = new QueryString("?parameter[hello]=Monday&parameter[world]=Tuesday&parameter[exclamation]=BadEnumValue");
1410+
});
1411+
1412+
var modelState = testContext.ModelState;
1413+
1414+
// Act
1415+
var modelBindingResult = await parameterBinder.BindModelAsync(parameter, testContext);
1416+
var model = Assert.IsType<Dictionary<string, DayOfWeek>>(modelBindingResult.Model);
1417+
1418+
// Assert
1419+
Assert.True(modelBindingResult.IsModelSet);
1420+
// Assert.Equal(expectedDictionary, model);
1421+
1422+
Assert.NotEmpty(modelState);
1423+
Assert.Equal(1, modelState.ErrorCount);
1424+
Assert.False(modelState.IsValid);
1425+
Assert.Equal("The value 'BadEnumValue' is not valid for Value.", modelState["parameter[exclamation]"].Errors[0].ErrorMessage);
1426+
}
1427+
13551428
#nullable enable
13561429
public class NonNullPersonWithRequiredProperties
13571430
{

0 commit comments

Comments
 (0)