paiden / Nett

.Net library for TOML
MIT License
223 stars 27 forks source link

Exception converting from Json to Toml #65

Closed NimaiMalle closed 5 years ago

NimaiMalle commented 5 years ago

I have the following code which, given a Json String, creates an object then attempts to get a Toml string from that object:

            object configurationObject = JsonConvert.DeserializeObject(jsonString);
            string contents = null;
            try
            {
                contents = Toml.WriteString(configurationObject);
            }
            catch (Exception e)
            {
                contents = e.Message;
            }

The value of jsonString happens to be {"MongoURL":"localhost","ElasticsearchUrls":"http://localhost:9200"}

The Exception is: Parameter count mismatch.

   at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
   at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
   at Nett.TomlTable.<From>g__CreateFromCustomClrObject|6_1[T](<>c__DisplayClass6_0`1& )
   at Nett.TomlTable.From[T](TomlSettings settings, T obj)
   at Nett.Toml.WriteString[T](T obj)

Maybe there's a better way to go from Json (or dynamic object) to Toml? I'll see about adding a test case for this, or let me know if what I'm doing is not the right approach.

paiden commented 5 years ago

That the attempt to serialize a JObject threw an exception was a bug that was fixed by commit ed16019. But serializing the JObject will produce the following content which surely is not what you expect

Type = "Object"
HasValues = true
First = [[]]
Last = [[]]
Count = 2
Root = [[[]], [[]]]
Path = ""

To get the expected content you have to do:

const string jsonString = @"{""MongoURL"":""localhost"",""ElasticsearchUrls"":""http://localhost:9200""}";
JObject configurationObject = (JObject)JsonConvert.DeserializeObject(jsonString);
var serMe = configurationObject.ToObject<Dictionary<string, object>>();
string contents = Toml.WriteString(serMe);

Same a little bit shorter:

const string jsonString = @"{""MongoURL"":""localhost"",""ElasticsearchUrls"":""http://localhost:9200""}";
var configurationObject = JsonConvert.DeserializeObject<Dictionary<string, object>>(jsonString);
string contents = Toml.WriteString(configurationObject);

This two variants should also work with the currently released version of the lib that does not contain the JObject fix.

NimaiMalle commented 5 years ago

Thank you! Just what I needed. I had taken a look inside of TomlTable.RootTabl.cs and was considering adding support for JObject much like IDictionary has a special case. So, something like the following:

            if ((object)obj is IDictionary dict)
            {
                CreateFromDictionary();
            }
            else if ((object)obj is JObject)
            {
                CreateFromJObject(obj as JObject);
            }
            else
            {
                CreateFromCustomClrObject();
            }

The create function would be almost identical to the IDictionary one. The approach you gave works just fine, though, so maybe not needed.

paiden commented 5 years ago

I don't think that a method like this is needed for the following reasons

NimaiMalle commented 5 years ago

Thank you for the explanation. Makes total sense.