graphql-platform icon indicating copy to clipboard operation
graphql-platform copied to clipboard

AnyType IDictionary serialize like JSON

Open steveoh opened this issue 4 years ago • 5 comments

Describe the bug

IDictionary<string, object> serialization as AnyType is weird.

To Reproduce

With the following query and output type

public class Query
{
    public Thing Query() => new Thing { Junk = new Dictionary<string, object> {{ "name", "yo" }}};
}

public class Thing {
  [GraphQLType(typeof(AnyType))] public IDictionary<string, object> Junk { get; set; }
}

An error is thrown EXEC_INVALID_LEAF_VALUE when querying.

If I change the dictionary type to IDictionary<string, string> then the serialization is weird

{
  "junk": [
    {
       "key": "name",
       "value": "yo"
    }
  ]
}

If I create a constructor to take the dictionary<string, object> and iterate over its values calling ToString then I get the expected result and that is weird.

foreach(var key in Junk.Keys) {
   Junk[key] = Junk[key].ToString();
}

But, I get the expected result

{
  "junk": {
    "name": "yo"
   }
}

Expected behavior

I expect IDictionary<string, object> to serialize like json

Desktop (please complete the following information):

  • OS: macos
  • Version: 10.15.7

steveoh avatar Apr 28 '21 23:04 steveoh

I'm also seeing this issue.

OS: macos Version: 11.3.0

louisoftokyo avatar Jun 22 '21 05:06 louisoftokyo

I am as well.

Windows 10 Visual studio 2019 Version 11.3.0

partial record CountryDto
{
    [GraphQLType(typeof(AnyType))]
    public IDictionary<string, string> Provinces { get; init; } = null!;
}

Results in the following if I run the query in Banana Cake Pop

{
  "data": {
    "country": {
      "name": "United States",
      "abbreviation": "us",
      "provinces": [
        {
          "key": "AL",
          "value": "Alabama"
        },
        {
          "key": "AK",
          "value": "Alaska"
        },

scottcollins avatar Jun 30 '21 23:06 scottcollins

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar May 04 '22 09:05 stale[bot]

Also faced this issue

RubcovMindbox avatar May 31 '22 13:05 RubcovMindbox

I added this test:

        [Fact]
        public async Task Output_Return_Dictionary()
        {
            // arrange
            ISchema schema = SchemaBuilder.New()
                .AddQueryType(d => d
                    .Name("Query")
                    .Field("foo")
                    .Type<AnyType>()
                    .Resolve(_ => new Dictionary<string, object> {
                        { "number", 123 },
                        { "dateTime", DateTime.UnixEpoch } }))
                .Create();

            IRequestExecutor executor = schema.MakeExecutable();

            // act
            IExecutionResult result = await executor.ExecuteAsync("{ foo }");

            // assert
            result.ToJson().MatchSnapshot();
        }

But the snapshot looks correct ...

{
  "data": {
    "foo": {
      "number": 123,
      "dateTime": "1970-01-01T00:00:00.000Z"
    }
  }
}

So I'm not sure what's going on in my case (and the case of the OP and others).

I'm using this in my Error type.

I need to look into it more.

glen-84 avatar Jun 17 '22 19:06 glen-84

Hello,

Do you think you will work on this subject ? I have to return yaml content files from my api (I parse the files and load them into Dictionary<string, object>) and need to have the capacity.

Maybe I found a workaround. Don't expose a Dictionary but a IReadOnlyDictionary as the AnyType ParseValue will do :

 if (value is IReadOnlyDictionary<string, object> dict)
            {
                var fields = new List<ObjectFieldNode>();
                foreach (var field in dict)
                {
                    fields.Add(new ObjectFieldNode(
                        field.Key,
                        ParseValue(field.Value, set)));
                }
                return new ObjectValueNode(fields);
            }

By changing my Dictionary type to IReadOnlyDictionary, I had the expected result

Before :

{
"capacities":[{"key":"SubnetProvider","value":true}]
}

After :

{
"capacities":{"SubnetProvider":true}
}

thank you

ygo74 avatar Nov 29 '22 16:11 ygo74

I have same error and the workaround exposing the Dictionary as IReadOnlyDictionary it doesn't work in my case, I'm still getting key/value pairs.

ernestfolch avatar Jan 10 '23 14:01 ernestfolch

The same thing happens to me, even after changing to IReadOnlyDictionary.

corinaivanov avatar Jan 11 '23 11:01 corinaivanov

Trying to debug this a bit, and for whatever reason, the runtime type is a KeyValuePair – that seems odd, shouldn't it be a dictionary?

image

glen-84 avatar Feb 10 '23 11:02 glen-84

A dictionary is basically ICollection<KeyValuePair<K,V>>.

Soundman32 avatar Feb 10 '23 17:02 Soundman32

A dictionary is basically ICollection<KeyValuePair<K,V>>.

Right, but KeyValuePair is the element type, not the type itself.

glen-84 avatar Feb 10 '23 18:02 glen-84

Use our new JsonType. Video coming out soon ...

michaelstaib avatar Feb 16 '23 16:02 michaelstaib

@michaelstaib

Use our new JsonType. Video coming out soon ...

If I do ...

    [GraphQLType<JsonType>]
    public required Dictionary<string, string> Fields { get; init; }

I get:

JSON cannot serialize the given value.

I don't think that the JSON type solves the original issue of serializing dictionaries specifically, not just any dynamic data.

If JSON serializes a Dictionary<string, object> (or <string, string>) as an object/map, one might expect that to be the default behaviour in Hot Chocolate.

glen-84 avatar Feb 23 '23 19:02 glen-84

I have reopened this to investigate the issue @glen-84 still has with the Any and JSON.

michaelstaib avatar Feb 24 '23 08:02 michaelstaib

I tested the issue in the OP, and I cannot reproduce it in HC 13.0.2.

Michael has said that only <string, object> is supported, not <string, string>.

@RubcovMindbox @ernestfolch @corinaivanov

Which type and generic arguments are you using?

glen-84 avatar Feb 24 '23 09:02 glen-84

I encountered similar issue.

Returning type

public record MyObjectState
{
    public string Id {get; set; }
    
    [GraphQLType(typeof(AnyType))]
    public IDictionary<string, object?>? Fields { get; set; }
}

GraphQL

  myObject(
    id: "cool-guid") {
    id
    fields
  }

MongoDB Database content

{
  "_id": "cool-guid",
  "fields": {
    "name": "MyName",
    "someOptionalValue": null,
    "someStringValue": "32",
    "dateOfBirth": {
      "$date": "2023-04-05T00:00:00.000Z"
    },
    "gender": "female",
    "nestedObject": {},
    "nestedArray": [
      {
        "name": "item1",
        "isOk": true,
        "rules": [
          {
            "node": "abra kadabra"
          }
        ],
        "dataFields": [
          "dateOfBirth",
          "name"
        ]
      },
      {
        "name": "item2",
        "isOk": true,
        "rules": [
          {
            "description": "hehe < 5"
          }
        ],
        "dataFields": [
          "dateOfBirth",
          "someStringValue"
        ]
      }
    ],
    "someCode": {
      "$numberLong": "0"
    }
  },
}

Error

{
  "errors": [
    {
      "message": "Unexpected Execution Error",
      "locations": [
        {
          "line": 19,
          "column": 3
        }
      ],
      "path": [
        "myObject",
        "fields"
      ],
      "extensions": {
        "message": "Parameter count mismatch.",
        "stackTrace": "   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitObject(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitObject(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitObject(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitObject(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitObject(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitObject(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitObject(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.Convert(Object obj)\n   at HotChocolate.Types.AnyType.TrySerialize(Object runtimeValue, Object& resultValue)\n   at HotChocolate.Types.ScalarType.Serialize(Object runtimeValue)\n   at HotChocolate.Execution.Processing.ValueCompletion.TryCompleteLeafValue(IOperationContext operationContext, MiddlewareContext resolverContext, ISelection selection, Path path, IType fieldType, Object result, Object& completedResult)",
        "code": "EXEC_INVALID_LEAF_VALUE",
        "remote": {
          "message": "Unexpected Execution Error",
          "locations": [
            {
              "line": 1,
              "column": 172
            }
          ],
          "path": [
            "myObject",
            "fields"
          ],
          "extensions": {
            "message": "Parameter count mismatch.",
            "stackTrace": "   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitObject(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitObject(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitObject(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitObject(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitObject(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitObject(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitList(ICollection list, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitObject(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.VisitValue(Object obj, Action`1 setValue, ISet`1 processed)\n   at HotChocolate.Utilities.ObjectToDictionaryConverter.Convert(Object obj)\n   at HotChocolate.Types.AnyType.TrySerialize(Object runtimeValue, Object& resultValue)\n   at HotChocolate.Types.ScalarType.Serialize(Object runtimeValue)\n   at HotChocolate.Execution.Processing.ValueCompletion.TryCompleteLeafValue(IOperationContext operationContext, MiddlewareContext resolverContext, ISelection selection, Path path, IType fieldType, Object result, Object& completedResult)",
            "code": "EXEC_INVALID_LEAF_VALUE"
          }
        },
        "schemaName": "mySchemaName"
      }
    }
  ],
  "data": {
    "myObject": {
      "id": "cool-guid",
      "fields": null
    }
  }
}

Spaier avatar Apr 06 '23 07:04 Spaier

For me it was JToken and ExpandoObject issues.

I had to convert JToken to Dictionary recursively instead of just using .ToObject<Dictionarty<string, object?>>

And I had to convert ExpandoObject to ReadOnlyDictionary. It's a dictionary already, but it seems HC expects only ReadOnly ones in ObjectToDictionaryConverter

Spaier avatar Apr 06 '23 10:04 Spaier

image

Spaier avatar Apr 06 '23 10:04 Spaier

@michaelstaib Does it make sense to add IDictionary in addition to IReadOnlyDictionary in ObjectToDictionaryConverter?

    private void VisitObject(
        object obj,
        Action<object> setValue,
        ISet<object> processed)
    {
        if (processed.Add(obj))
        {
            var dict = new Dictionary<string, object>();
            setValue(dict);

            if (obj is IReadOnlyDictionary<string, object> d)
            {
                foreach (KeyValuePair<string, object> item in d)
                {
                    Action<object> setField = v => dict[item.Key] = v;
                    VisitValue(item.Value, setField, processed);
                }
            }
            else
            {
                foreach (PropertyInfo property in GetProperties(obj))
                {
                    string name = property.GetGraphQLName();
                    object value = property.GetValue(obj);
                    Action<object> setField = v => dict[name] = v;
                    VisitValue(value, setField, processed);
                }
            }
        }
    }

Spaier avatar Apr 06 '23 10:04 Spaier

I have moved this to 13.4 to refine the Any type further.

michaelstaib avatar Jun 02 '23 18:06 michaelstaib