splunk / splunk-sdk-csharp-pcl

Splunk's next generation C# SDK
https://dev.splunk.com/enterprise/docs/csharp
Apache License 2.0
64 stars 46 forks source link

SavedSearches.CreateAsync(string, string) Fails with System.ArgumentException : An item with the same key has already been added #99

Closed ewan-derivco closed 2 years ago

ewan-derivco commented 4 years ago

Calling the SavedSearches.CreateAsync method with a name and search, creates the search but throws an exception, regardless of the name you send

System.ArgumentException : An item with the same key has already been added.

Sample code:

        using (var service = new Service(
            Scheme.Https,
            server,
            8089,
            new Namespace(user: "nobody", app: "itsi")
            ))
        {
            await service.LogOnAsync(username, password);

            await service.SavedSearches.CreateAsync("test search via api4", "index= test"); //fails regardless of name but saved search _is_ created

            await service.SavedSearches.GetAllAsync();

            foreach(var ss in service.SavedSearches.Where(i=>i.Namespace.App == "itsi"))
            {
                Console.WriteLine($"{ss.Name} {ss.Namespace}");
            }
        }
ewan-derivco commented 4 years ago

On investigation this seem sot be a problem in ParseDictionaryAsync

The name is split and only the last bit used. But this Causes duplicates for the saved search response.

                propertyName = NormalizePropertyName(names[names.Length - 1]);
                propertyValue = await ParsePropertyValueAsync(reader, level + 1).ConfigureAwait(false);
                dictionary.Add(propertyName, propertyValue);

https://docs.splunk.com/Documentation/Splunk/7.2.1/RESTREF/RESTsearch

ewan-derivco commented 4 years ago

OK. looking further at that fuction, it looks like the ITSI app adds some extra properties onto the SavedSearch reply which fall afoul of the "fields which are a value and a dictionary" problem which has a hard-coded solution in ParseDictionaryAsync

to fix I added a dynamic solution, for when a non dictionary value is found. this retroactively changes the value to a dictionary and adds the old value under the key "value" in that dictionary.

not tested!

                ```
 for (int i = 0; i < names.Length - 1; i++)
                {
                    propertyName = NormalizePropertyName(names[i]);

                    if (dictionary.TryGetValue(propertyName, out propertyValue))
                    {
                        if (!(propertyValue is Dictionary<string, object>))
                        {
                            //duplicate property name. this needs to be added to the list above
                            var newVal = new Dictionary<string, object>();
                            newVal.Add("value", propertyValue);
                            dictionary[propertyName] = newVal;

                            propertyValue = dictionary[propertyName];
                        }
                    }
                    else
                    {
                        propertyValue = new Dictionary<string, object>();
                        dictionary.Add(propertyName, propertyValue);
                    }

                    dictionary = propertyValue;
                }
ncanumalla-splunk commented 2 years ago

This SDK is deprecated and no longer under active development.