Weird Serialization error



  • I get random serialization issues. I am not sure if it's an issue with JS Reports though. I think it may be an issue with the Simple OData client or maybe the JSReports .NET Types project.

    If i run this code in C#, i get an error of "Object of type 'System.String' cannot be converted to type 'System.Nullable`1[jsreport.Types.Recipe]'."

    var test1 = await client.For<Template>()
                            .Filter($"name eq '{Request.Form["renderFormat"]}' and ({string.Join(" or ", folderList.Select(l => "folder/shortid eq '" + l + "'").ToArray())})")
                            .FindEntryAsync();
    

    This code generates the following OData query (which is correct)

    This sends the request and gets back the following response from JSReports:

    {
      "@odata.context": "https://MYSERVER/odata/$metadata#templates",
      "value": [
        {
          "name": "pdf",
          "recipe": "chrome-pdf",
          "shortid": "BJeNk5lmfw",
          "engine": "handlebars",
          "chrome": {
            "printBackground": true
          },
          "creationDate": "2020-08-13T17:35:44.635Z",
          "modificationDate": "2020-08-14T14:07:14.324Z",
          "inheritedReadPermissions": [],
          "inheritedEditPermissions": [],
          "data": {
            "shortid": "HyeDCMAbfv"
          },
          "resources": {
            "items": [],
            "defaultLanguage": ""
          },
          "scripts": [
            {
              "shortid": "SJlgz-JXfv"
            }
          ],
          "_id": "AcfiqLZpThqQySNd",
          "content": "MY CONTENT HERE",
          "helpers": "function formatDate(date){\r\n  console.log(\"formatting date\")\r\n  moment = require('moment');\r\n  return moment(date).format(\"M/D/YYYY\");\r\n}\r\n\r\nfunction groupedData(data){\r\n    return buildData(group(data));\r\n}\r\nfunction group(data){\r\n  let group = data.reduce((r, a) => {\r\n   r[a.TaskCode] = [...r[a.TaskCode] || [], a];\r\n   return r;\r\n  }, {});\r\n  return group;\r\n}\r\n\r\nfunction buildData(data){\r\n\tvar obj = {\"Data\": []}\r\n\tObject.keys(data).forEach(function(key, index){\r\n    obj[\"Data\"][index] = {\"TaskCode\": key, \"Milestones\": data[key]}\r\n  });\r\n  return obj;\r\n}\r\n\r\n",
          "folder": {
            "shortid": "gKhiKDU"
          }
        }
      ]
    }
    

    Just to test that it's not the query or OData, i ran the following C# code and it produced the correct dictionary of values

    var test = await client.For("template")
                            .Filter($"name eq '{Request.Form["renderFormat"]}' and ({string.Join(" or ", folderList.Select(l => "folder/shortid eq '" + l + "'").ToArray())})")
                            .FindEntryAsync();
    

    If I use a template with a recipe of "html" this error doesn't happen. I have already had to create my own class to be able to handle Folder/ShortId while waiting for your next update, do you think this can be resolved by overriding Recipe? Here is what I have had to do to create my own class that i use for other templates (I created a reusable fodler and i know most of those DataMember attributes don't need to be there...i was testing)

        public class Folder
        {
            [System.Runtime.Serialization.DataMember(Name = "shortid")]
            public string Shortid { get; set; }
    
            [System.Runtime.Serialization.DataMember(Name = "name")]
            public string Name { get; set; }
    
            [System.Runtime.Serialization.DataMember(Name = "folder")]
            public Folder ParentFolder { get; set; }
        }
    
        public class TempTemplate : jsreport.Types.Template
        {
    
            [System.Runtime.Serialization.DataMember(Name = "folder")]
            public Folder Folder { get; set; }
        }
    


  • Here is the stacktrace for the error as well

    at System.RuntimeType.TryChangeType(Object value, Binder binder, CultureInfo culture, Boolean needsSpecialCast)
    at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig)
    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.SetValue(Object obj, Object value, Object[] index)
    at Simple.OData.Client.Extensions.DictionaryExtensions.ToObject(IDictionary2 source, ITypeCache typeCache, Type type, Boolean dynamicObject) at Simple.OData.Client.Extensions.DictionaryExtensions.ToObject[T](IDictionary2 source, ITypeCache typeCache, Boolean dynamicObject)
    at System.Linq.Enumerable.WhereSelectListIterator2.MoveNext() at System.Linq.SystemCore_EnumerableDebugView1.get_Items()



  • This is definitely an issue with the Simple OData Client.

    You can see in their source that they are trying to use Enum.Parse which will not take the data annotations in to account
    https://github.com/simple-odata-client/Simple.OData.Client/blob/5d2cc4d93fdb98a93e3966d10d1ae5b038017831/src/Simple.OData.Client.Core/Extensions/DictionaryExtensions.cs

    I worked around it using

    
        public class TempTemplate : jsreport.Types.Template
        {
            string tmpRecipe;
    
            [System.Runtime.Serialization.DataMember(Name = "folder")]
            public Folder Folder { get; set; }
    
            public new string Recipe
            {
                get {
                    return tmpRecipe;
                }
                set
                {
                    tmpRecipe = value;
                    base.Recipe = JsonConvert.DeserializeObject<Recipe>($"\"{value}\"");
                }
            }
        }
    


  • I solve this problem this way:

    var rawObject = await client.For("template")
    .Filter("folder/shortid eq 'CHJwoyR'")
    .FindEntryAsync();
    var jsonStirng = JsonConvert.SerializeObject(rawObject);
    var template = JsonConvert.DeserializeObject<Template>(jsonStirng);


Log in to reply
 

Looks like your connection to jsreport forum was lost, please wait while we try to reconnect.