Skip to content
This repository has been archived by the owner on Nov 15, 2018. It is now read-only.

Support DynamicObject types #99

Merged
merged 7 commits into from
Aug 24, 2017
Merged

Support DynamicObject types #99

merged 7 commits into from
Aug 24, 2017

Conversation

jbagga
Copy link
Contributor

@jbagga jbagga commented Aug 7, 2017

Addresses #38

cc @kichalla @rynowak

{
errorMessage = null;
nextTarget = null;
return false;
}

var dictionary = (IDictionary<string, object>)expandoObject;
var dictionary = (IDictionary<string, object>)dynamicObject;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a good assumption. We need to use IDynamicMetaObjectProvider directly.

@jbagga
Copy link
Contributor Author

jbagga commented Aug 15, 2017

@rynowak Added a new adapter instead of replacing ExpandoObjectAdapter.

object value,
out string errorMessage)
{
if(!TrySetDynamicObjectProperty(target, contractResolver, segment, value))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spacing

nextTarget = null;
errorMessage = null;
return false;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Under what conditions can this happen? Should we be checking this in all of these methods and returning a good error message?


var propertyName = jsonDynamicContract?.PropertyNameResolver(segment);

var binder = CSharp.RuntimeBinder.Binder.GetMember(CSharpBinderFlags.None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newline after (

var binder = CSharp.RuntimeBinder.Binder.GetMember(CSharpBinderFlags.None,
propertyName,
target.GetType(),
new List<CSharpArgumentInfo>{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string segment,
out object property)
{
var jsonDynamicContract = contractResolver.ResolveContract(target.GetType()) as JsonDynamicContract;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Under what conditions do we expect this cast to fail?

{
var jsonDynamicContract = contractResolver.ResolveContract(target.GetType()) as JsonDynamicContract;

var propertyName = jsonDynamicContract?.PropertyNameResolver(segment);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll get an ArgumentNullException later at line 156. If you are going to be defensive, make sure you are defending from the right things

{
property = null;
return false;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we put a try/catch around the rest of our property set logic?

This seems really dangerous

@jbagga
Copy link
Contributor Author

jbagga commented Aug 17, 2017

@rynowak Updated

propertyName,
var binder = CSharp.RuntimeBinder.Binder.GetMember(
CSharpBinderFlags.None,
propertyName ?? segment,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rynowak If segment is null it will throw here before it gets to the adapter.

If the contract or the propertName cannot be resolved, segment may still be a valid path for the patch document. Is that risky?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah but under what conditions would any of these things happen?

out object property,
out string errorMessage)
{
var jsonDynamicContract = contractResolver.ResolveContract(target.GetType()) as JsonDynamicContract;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When can this cast fail? I think you're being defensive here with something that can't happen


var propertyName = jsonDynamicContract?.PropertyNameResolver(segment);

var binder = CSharp.RuntimeBinder.Binder.GetMember(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a .using if possible. If there's a conflict then use using CSharpBinder = ...

object target,
IContractResolver contractResolver,
string segment,
out object property,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't the right name, it's the property's value not the property itself

new List<CSharpArgumentInfo>
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this right? I would expect the getter to have only one argument (this).

var serialized = JsonConvert.SerializeObject(patchDoc);
var deserialized = JsonConvert.DeserializeObject<JsonPatchDocument>(serialized);

deserialized.ApplyTo(doc);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need this? I think that you should be able to use patchDoc directly

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that's how I wrote them but again for consistency with existing tests I changed them to use deserialized. I'll change them to use patchDoc instead

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, don't copy bad stuff 😆

[Fact]
public void AddNewPropertyToDynamicOjectInTypedObject()
{
var doc = new NestedDTO()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

avoid abbreviations like this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So rename this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neither doc nor NestedDTO are great names

using Newtonsoft.Json;
using Xunit;

namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't really the right namespace.


namespace Microsoft.AspNetCore.JsonPatch.Test.Dynamic
{
public class DynamicObjectAdapterTests
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these are unit tests then there should be calling methods on the adapter directly.

If these are integration tests, we should organize them as such.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to be consistent with https://github.com/aspnet/JsonPatch/blob/dev/test/Microsoft.AspNetCore.JsonPatch.Test/Dynamic/AddOperationTests.cs and other tests here. Should I move my tests to the existing test classes? They are organized by OperationType, not by Adapters.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sending one of my minions to help you sort out this mess later today. Don't fret, help is on the way

}

[Fact]
public void ReplaceAtEndOfList()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is wayyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy overtesting for dynamic. Most of these really feel like integration tests.

@jbagga
Copy link
Contributor Author

jbagga commented Aug 24, 2017

@rynowak Added unit tests

out object value,
out string errorMessage)
{
var jsonDynamicContract = contractResolver.ResolveContract(target.GetType()) as JsonDynamicContract;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please stop by so we can discuss this in person. I've commented on this about 4 times and haven't yet heard and answer.

// Assert
Assert.False(removeStatus);
Assert.Equal($"The target location specified by path segment '{segment}' was not found.", removeErrorMessage);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are good 👍

@jbagga
Copy link
Contributor Author

jbagga commented Aug 24, 2017

@rynowak Updated

@jbagga jbagga merged commit 3d6a861 into dev Aug 24, 2017
@jbagga jbagga deleted the jbagga/DynamicTypes38 branch August 24, 2017 22:11
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants