-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Handle broader range of collection types in model binding #2946
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
// Copyright (c) .NET Foundation. 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.Diagnostics; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using Microsoft.Framework.Internal; | ||
|
@@ -25,15 +27,29 @@ public override Task<ModelBindingResult> BindModelAsync([NotNull] ModelBindingCo | |
return base.BindModelAsync(bindingContext); | ||
} | ||
|
||
protected override object CreateEmptyCollection() | ||
/// <inheritdoc /> | ||
public override bool CanCreateInstance(Type targetType) | ||
{ | ||
Debug.Assert(targetType == typeof(TElement[]), "GenericModelBinder only creates this binder for arrays."); | ||
|
||
return true; | ||
} | ||
|
||
/// <inheritdoc /> | ||
protected override object CreateEmptyCollection(Type targetType) | ||
{ | ||
Debug.Assert(targetType == typeof(TElement[]), "GenericModelBinder only creates this binder for arrays."); | ||
|
||
return new TElement[0]; | ||
} | ||
|
||
/// <inheritdoc /> | ||
protected override object GetModel(IEnumerable<TElement> newCollection) | ||
protected override object ConvertToCollectionType(Type targetType, IEnumerable<TElement> collection) | ||
{ | ||
return newCollection?.ToArray(); | ||
Debug.Assert(targetType == typeof(TElement[]), "GenericModelBinder only creates this binder for arrays."); | ||
|
||
// If non-null, collection is a List<TElement>, never already a TElement[]. | ||
return collection?.ToArray(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will the default case here be that the model is already an array? What are the cases we might get here and have it not be an array? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It'll never be an array since the base There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool! Can you add that info to a comment here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👌 |
||
} | ||
|
||
/// <inheritdoc /> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,13 @@ | ||
// Copyright (c) .NET Foundation. 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.Diagnostics; | ||
using System.Linq; | ||
#if DNXCORE50 | ||
using System.Reflection; | ||
#endif | ||
using System.Threading.Tasks; | ||
using Microsoft.Framework.Internal; | ||
|
||
|
@@ -27,7 +31,7 @@ public override async Task<ModelBindingResult> BindModelAsync([NotNull] ModelBin | |
} | ||
|
||
Debug.Assert(result.Model != null); | ||
var model = (Dictionary<TKey, TValue>)result.Model; | ||
var model = (IDictionary<TKey, TValue>)result.Model; | ||
if (model.Count != 0) | ||
{ | ||
// ICollection<KeyValuePair<TKey, TValue>> approach was successful. | ||
|
@@ -80,15 +84,37 @@ public override async Task<ModelBindingResult> BindModelAsync([NotNull] ModelBin | |
} | ||
|
||
/// <inheritdoc /> | ||
protected override object GetModel(IEnumerable<KeyValuePair<TKey, TValue>> newCollection) | ||
protected override object ConvertToCollectionType( | ||
Type targetType, | ||
IEnumerable<KeyValuePair<TKey, TValue>> collection) | ||
{ | ||
return newCollection?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); | ||
if (collection == null) | ||
{ | ||
return null; | ||
} | ||
|
||
if (targetType.IsAssignableFrom(typeof(Dictionary<TKey, TValue>))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What will There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, a comment would make it must more clear 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this iteration includes a comment I added 2 lines below. |
||
{ | ||
// Collection is a List<KeyValuePair<TKey, TValue>>, never already a Dictionary<TKey, TValue>. | ||
return collection.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); | ||
} | ||
|
||
var newCollection = CreateInstance(targetType); | ||
CopyToModel(newCollection, collection); | ||
|
||
return newCollection; | ||
} | ||
|
||
/// <inheritdoc /> | ||
protected override object CreateEmptyCollection() | ||
protected override object CreateEmptyCollection(Type targetType) | ||
{ | ||
return new Dictionary<TKey, TValue>(); | ||
if (targetType.IsAssignableFrom(typeof(Dictionary<TKey, TValue>))) | ||
{ | ||
// Simple case such as IDictionary<TKey, TValue>. | ||
return new Dictionary<TKey, TValue>(); | ||
} | ||
|
||
return CreateInstance(targetType); | ||
} | ||
|
||
private static TKey ConvertFromString(string keyString) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why just do the thing you put in the assert? You could say with like 20 characters what all of this does, and technically be more correct 😆
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done