0

I am trying to return some data to a webservice using json and the JSon.Net library. One of my functions is an iterator method that lists data using yield return. When I try to serialize this return value, I am getting an invalid operation exception

I am using string jsonEncoded = JsonConvert.SerializeObject(ret, Formatting.Indented); to serialize the return value.

The full stack trace of the exception is:

System.InvalidOperationException: This operation is only valid on generic types.
   at System.RuntimeType.GetGenericTypeDefinition()
   at Newtonsoft.Json.Serialization.JsonArrayContract..ctor(Type underlyingType) in c:\Temp\Json\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonArrayContract.cs:line 148
   at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateArrayContract(Type objectType) in c:\Temp\Json\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\DefaultContractResolver.cs:line 686
   at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateContract(Type objectType) in c:\Temp\Json\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\DefaultContractResolver.cs:line 800
   at Newtonsoft.Json.Serialization.DefaultContractResolver.ResolveContract(Type type) in c:\Temp\Json\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\DefaultContractResolver.cs:line 232
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.GetContractSafe(Object value) in c:\Temp\Json\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalWriter.cs:line 83
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType) in c:\Temp\Json\Working\Newtonsoft.Json\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalWriter.cs:line 67
   at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType) in c:\Temp\Json\Working\Newtonsoft.Json\Src\Newtonsoft.Json\JsonSerializer.cs:line 753
   at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value, Type objectType) in c:\Temp\Json\Working\Newtonsoft.Json\Src\Newtonsoft.Json\JsonSerializer.cs:line 668
   at Newtonsoft.Json.JsonConvert.SerializeObject(Object value, Type type, Formatting formatting, JsonSerializerSettings settings) in c:\Temp\Json\Working\Newtonsoft.Json\Src\Newtonsoft.Json\JsonConvert.cs:line 921
   at Newtonsoft.Json.JsonConvert.SerializeObject(Object value, Formatting formatting, JsonSerializerSettings settings) in c:\Temp\Json\Working\Newtonsoft.Json\Src\Newtonsoft.Json\JsonConvert.cs:line 893
   at Newtonsoft.Json.JsonConvert.SerializeObject(Object value, Formatting formatting) in c:\Temp\Json\Working\Newtonsoft.Json\Src\Newtonsoft.Json\JsonConvert.cs:line 837
   at AladdinWeb.Handlers.AladdinHandler.ProcessRequest(HttpContext context) in C:\Users\mehrlich\Projects\AladdinWeb\AladdinWeb\Server\Handlers\AladdinHandler.cs:line 85 [ 15/04/2013 11:24:24.68135 ]

The signature of the iterator method is:

public IEnumerable<dynamic> FunctionName() { ... }

As of now, I have a temporary solution in place by checking for calls to this function and calling ToList on the return value. This serializes just fine, but it is kind of an ugly solution since I need to have a special case for it (and any other iterator methods I might add). My guess is that this has to do with the IEnumerable not being enumerated.

Can I get Json.Net to serialize the result of my iterator functions or will I always need a special case like this? Let me know if any more information or source code is needed and I will post it.

More Info: I am using the .Net framework version 4.0 and I am using Json.Net version 5.0r2

Abridged Source Code of the Iterator Method

public IEnumerable<dynamic> FunctionName()
{
    var methodList = typeof(Targets).GetMethods();

    foreach (var m in methodList)
    {
        dynamic info = new ExpandoObject();

        info.Name = m.Name;

        info.Parameters = from param in m.GetParameters()
                                  select param.Name;

        yield return info;
    }
}

Source Code of Method Call

...
object ret = null;
if (q == "FunctionName")
{
    ret = FunctionName();  // This causes an exception to be thrown later
    // ret = FunctionName().ToList(); // This does NOT throw an exception later
}
else
{
    ret = DoOtherStuff(q, request);
}

// Serialize the result to JSON 
// This line throws the exception
string jsonEncoded = JsonConvert.SerializeObject(ret, Formatting.Indented);
...
Max Ehrlich
  • 2,479
  • 1
  • 32
  • 44
  • 1
    I'm not sure you can call serialise on that type of iterator method. Do you not know the type that FunctionName returns at compile time? Also calling ToList() I assume you then cast to a specific type at that point? – TheKingDave Apr 15 '13 at 15:57
  • 1
    http://stackoverflow.com/questions/5156664/how-to-flatten-an-expandoobject-returned-via-jsonresult-in-asp-net-mvc - it may just be a problem that JSON.Net has dealing with dynamic objects; they can be flattened to dictionaries, at which point your problem may go away. – 48klocs Apr 15 '13 at 16:09
  • @TheKingDave Do you mean that I cannot serialize `IEnumerable`? I have tried changing the function to `IEnumerable` as well and it didn't change anything. As for the second part, no I am not casting, I simply call `object ret = FunctionName().ToList()` – Max Ehrlich Apr 15 '13 at 16:10
  • @48klocs That is unlikely. I am using `ExpandoObject`. It serializes fine when I return a single `ExpandoObject` and serializes fine when it is in a `List`, it is just this call to an iterator method that returns `ExpandoObject`s that is failing. Also I have tried explicitly returning `IEnumerable`and it didn't change anything. – Max Ehrlich Apr 15 '13 at 16:14
  • 1
    Serializing `yield return`-created `IEnumerable` seems to work for me. Could you include complete (but short) code that shows your problem? Also, what version of JSON.NET are you using? – svick Apr 15 '13 at 20:03
  • 1
    So then as you say JSON.Net is not enumerating as this is an iterator method. If you set a breakpoint within your method is it called as you would expect when you don't use ToList()? – TheKingDave Apr 16 '13 at 08:34
  • @TheKingDave Ok that was interesting. I cannot enumerate the result, i get the following error in the debugger `'AladdinWeb.Handlers.AladdinHandler.FunctionName()' is a 'method' but is used like a 'type'` – Max Ehrlich Apr 16 '13 at 12:34
  • @svick I updated my post with the information you requested – Max Ehrlich Apr 16 '13 at 12:46
  • @MaxEhrlich The updated code still works fine for me (if I create dummy `Targets` class). I was serious when I said you should post *complete* code. The best way to do that is if you create a small console application, that shows the issue and post all of its code here. – svick Apr 16 '13 at 19:58
  • @svick Yes I actually found that this exact bug was the purpose of a new JSon.Net release. I updated to 5.0r3 and it works fine. I was waiting in case you wanted to post the answer to give you credit since you posted asking about version numbers. – Max Ehrlich Apr 17 '13 at 00:28

1 Answers1

2

This issue is a bug with JSon.Net version 5.0r2, updating to 5.0r3 will fix this and in fact was the only reason for the 5.0r3 release.

Max Ehrlich
  • 2,479
  • 1
  • 32
  • 44
  • 1
    Thank you! I was installing a nuget feed from EPiServer and was pulling my hair out trying to figure out what's wrong with the nuget package for quite some time as suddenly my app shows the error reported above!! I finally found out that one of its dependencies was Newtonsoft.Json 5.0.1, so it ended up grading to this version and therefore getting the bug. I tried your suggestion and it now works. Thanks a million! – Nicola Jul 16 '16 at 12:23