New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix DefaultBinder conversions from Dictionary<string,object> #2052
Conversation
…The following example will work and not crash: binder = new DefaultBinder(new DefaultFieldNameConverter()); result = new[] { new Dictionary<string, object> { { "key", "value" } } }; binder.Bind(result, typeof(Dictionary<string, object>[]));
What's the go here? Is there actually a bug? |
There is but I have to take a deep look at it, that's why I closed it for now. I'll re-open later. |
…The following example will work and not crash: binder = new DefaultBinder(new DefaultFieldNameConverter()); result = new[] { new Dictionary<string, object> { { "key", "value" } } }; binder.Bind(result, typeof(Dictionary<string, object>[]));
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.
I think there is a cleaner way to resolve this, comments made inline.
Before this can be merged we'll need to add some code examples/use cases to BindingTest.html
. Unit Tests
probably should be added......
@@ -72,6 +72,10 @@ public virtual object Bind(object obj, Type modelType) | |||
{ | |||
throw new ArgumentException("When modelType is an enumerable it must specify the type.", "modelType"); | |||
} | |||
} | |||
else if (modelType.IsGenericObject()) |
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.
Type checking here seems a little weak, I think we'd be better off immediately after the obj == null
check to using something like
//If the object can be directly assigned to the modelType then return immediately.
if(modelType.IsAssignableFrom(obj.GetType()))
{
return obj;
}
/// </summary> | ||
/// <param name="source">source type</param> | ||
/// <returns>return true if is a generic js object</returns> | ||
public static bool IsGenericObject(this Type source) |
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.
The name of this method is confusing, I look at it and think of .Net generics
, I don't actually think it's required either if we make a few other simplifications.
@@ -94,7 +103,7 @@ public static bool IsAssignableToGenericType(this Type givenType, Type genericTy | |||
/// </summary> | |||
/// <param name="source">The type to check.</param> | |||
/// <returns><see langword="true" /> if the type is an collection, otherwise <see langword="false" />.</returns> | |||
public static bool IsCollection(this Type source) | |||
private static bool IsCollection(this Type source) |
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.
Reason for making this private is?
//If the type is a dictionary and the PropertyType isn't then we'll bind. | ||
if (obj.GetType() == dictionaryType && modelProperty.PropertyType != dictionaryType) | ||
if (obj.GetType().IsGenericObject() && !modelProperty.PropertyType.IsGenericObject()) |
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.
As the two if
branches here are duplicated I think we can simplify the whole BindValue
method. We should be able to simplify things quite a bit, using something like the following.
protected virtual void BindValue(BindingMemberInfo modelProperty, object obj, BindingContext context)
{
if(obj == null)
{
return;
}
if (modelProperty.PropertyType.IsAssignableFrom(obj.GetType()))
{
//Simply set the property
modelProperty.SetValue(context.Model, obj);
}
else
{
//Cannot directly set the property attempt to bind
var model = Bind(obj, modelProperty.PropertyType);
modelProperty.SetValue(context.Model, model);
}
}
@@ -190,7 +192,7 @@ protected virtual object CreateModel(Type modelType, Type genericType) | |||
|
|||
protected virtual object GetValue(string propertyName, BindingContext context) | |||
{ | |||
if (context.Object.GetType() == typeof(Dictionary<string, object>)) | |||
if (context.Object.GetType().IsGenericObject()) |
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.
Please revert this and remove IsGenericObject
extension method.
@@ -67,7 +66,17 @@ public static bool IsArray(this Type source) | |||
/// <returns>return if collection, array or enumerable</returns> | |||
public static bool IsCollectionOrArray(this Type source) | |||
{ | |||
return source.IsCollection() || source.IsArray() || source.IsEnumerable(); | |||
return !source.IsGenericObject() && (source.IsCollection() || source.IsArray() || source.IsEnumerable()); |
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.
I'm hopeful we can revert this change with the other changes I've proposed.
@@ -92,7 +96,7 @@ public virtual object Bind(object obj, Type modelType) | |||
|
|||
if (val != null) | |||
{ | |||
if (val.GetType() == typeof(Dictionary<string, object>)) | |||
if (val.GetType().IsGenericObject()) |
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.
Please revert this and remove IsGenericObject
extension method.
… - greatly simplifies the code Remove IsCollectionOrArray extension method, use the long hand - makes the code more readable. Switch to using Activator.CreateInstance directly Remove a large number of unused extensions in ModelBindingExtensions Alternate to #2052
I've merged my proposed changes in commit 0d48e30 Code is greatly simplified. If your still experiencing a problem I believe the simplifications are a better starting point for any further bug fixes. Where possible please include a test case that reproduces your problem, would make my life a lot easier, thank you. |
It works as expected, great! |
The following example will work and not crash: