dotnet / interactive

.NET Interactive combines the power of .NET with many other languages to create notebooks, REPLs, and embedded coding experiences. Share code, explore data, write, and learn across your apps in ways you couldn't before.
MIT License
2.85k stars 381 forks source link

Display of `Newtonsoft.Json.Linq.JObject` throws TargetInvocationException exception #2877

Open IvanAntipov opened 1 year ago

IvanAntipov commented 1 year ago

The bug

Display of Newtonsoft.Json.Linq.JObject throws TargetInvocationException exception

I am trying to execute the following

#r "nuget: Newtonsoft.Json"
Newtonsoft.Json.Linq.JToken.Parse("{a:1}")

And I get

Error: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.NotImplementedException: The method or operation is not implemented.
at Newtonsoft.Json.Linq.JObject.System.Collections.Generic.IDictionary<System.String,Newtonsoft.Json.Linq.JToken>.get_Values()
at InvokeStub_IDictionary`2.get_Values(Object, Object, IntPtr*)
at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
--- End of inner exception stack trace ---
at System.Reflection.MethodInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
at Microsoft.DotNet.Interactive.Formatting.TypeExtensions.<>c__DisplayClass14_0.<IsDictionary>b__3(Object instance) in D:\a\_work\1\s\src\Microsoft.DotNet.Interactive.Formatting\TypeExtensions.cs:line 276
at Microsoft.DotNet.Interactive.Formatting.HtmlFormatter`1.<>c__DisplayClass7_0.<CreateTableFormatterForAnyEnumerable>b__2(T instance) in D:\a\_work\1\s\src\Microsoft.DotNet.Interactive.Formatting\HtmlFormatter{T}.cs:line 71
at Microsoft.DotNet.Interactive.Formatting.HtmlFormatter`1.<>c__DisplayClass7_0.<CreateTableFormatterForAnyEnumerable>g__BuildTable|4(T source, FormatContext context, Boolean summarize) in D:\a\_work\1\s\src\Microsoft.DotNet.Interactive.Formatting\HtmlFormatter{T}.cs:line 99
at Microsoft.DotNet.Interactive.Formatting.HtmlFormatter`1.<>c__DisplayClass7_0.<CreateTableFormatterForAnyEnumerable>b__3(T value, FormatContext context) in D:\a\_work\1\s\src\Microsoft.DotNet.Interactive.Formatting\HtmlFormatter{T}.cs:line 83
at Microsoft.DotNet.Interactive.Formatting.HtmlFormatter`1.Format(T value, FormatContext context) in D:\a\_work\1\s\src\Microsoft.DotNet.Interactive.Formatting\HtmlFormatter{T}.cs:line 53
at Microsoft.DotNet.Interactive.Formatting.HtmlFormatter.<>c.<.cctor>b__0_12(IEnumerable value, FormatContext context) in D:\a\_work\1\s\src\Microsoft.DotNet.Interactive.Formatting\HtmlFormatter.cs:line 198
at Microsoft.DotNet.Interactive.Formatting.HtmlFormatter`1.Format(T value, FormatContext context) in D:\a\_work\1\s\src\Microsoft.DotNet.Interactive.Formatting\HtmlFormatter{T}.cs:line 53
at Microsoft.DotNet.Interactive.Formatting.Formatter.<>c__DisplayClass53_0.<TryInferPreferredFormatter>b__4(Object value, FormatContext context) in D:\a\_work\1\s\src\Microsoft.DotNet.Interactive.Formatting\Formatter.cs:line 702
at Microsoft.DotNet.Interactive.Formatting.AnonymousTypeFormatter`1.Format(T instance, FormatContext context) in D:\a\_work\1\s\src\Microsoft.DotNet.Interactive.Formatting\AnonymousTypeFormatter{T}.cs:line 30
at Microsoft.DotNet.Interactive.Formatting.Formatter`1.FormatTo(T obj, FormatContext context, String mimeType) in D:\a\_work\1\s\src\Microsoft.DotNet.Interactive.Formatting\Formatter{T}.cs:line 79
at Microsoft.DotNet.Interactive.Formatting.Formatter.FormatTo[T](T obj, FormatContext context, String mimeType) in D:\a\_work\1\s\src\Microsoft.DotNet.Interactive.Formatting\Formatter.cs:line 308
at Microsoft.DotNet.Interactive.Formatting.Formatter.ToDisplayString(Object obj, String mimeType) in D:\a\_work\1\s\src\Microsoft.DotNet.Interactive.Formatting\Formatter.cs:line 265
at Microsoft.DotNet.Interactive.FormattedValue.<>c__DisplayClass7_0.<FromObject>b__0(String mimeType) in D:\a\_work\1\s\src\Microsoft.DotNet.Interactive\FormattedValue.cs:line 37
at System.Linq.Enumerable.SelectArrayIterator`2.ToArray()
at Microsoft.DotNet.Interactive.FormattedValue.FromObject(Object value, String[] mimeTypes) in D:\a\_work\1\s\src\Microsoft.DotNet.Interactive\FormattedValue.cs:line 36
at Microsoft.DotNet.Interactive.CSharp.CSharpKernel.Microsoft.DotNet.Interactive.IKernelCommandHandler<Microsoft.DotNet.Interactive.Commands.SubmitCode>.HandleAsync(SubmitCode submitCode, KernelInvocationContext context) in D:\a\_work\1\s\src\Microsoft.DotNet.Interactive.CSharp\CSharpKernel.cs:line 351
at Microsoft.DotNet.Interactive.Kernel.HandleAsync(KernelCommand command, KernelInvocationContext context) in D:\a\_work\1\s\src\Microsoft.DotNet.Interactive\Kernel.cs:line 326
at Microsoft.DotNet.Interactive.KernelCommandPipeline.<BuildPipeline>b__6_0(KernelCommand command, KernelInvocationContext context, KernelPipelineContinuation _) in D:\a\_work\1\s\src\Microsoft.DotNet.Interactive\KernelCommandPipeline.cs:line 60
at Microsoft.DotNet.Interactive.KernelCommandPipeline.SendAsync(KernelCommand command, KernelInvocationContext context) in D:\a\_work\1\s\src\Microsoft.DotNet.Interactive\KernelCommandPipeline.cs:line 51

Despite the success of System.Text.Json Newtonsoft is still popular, and it is very common to deal with Newtonsoft objects in interactive.

Workaround

For a moment I use the following workaround

using System.Text;
using System.IO;
using Microsoft.DotNet.Interactive.Formatting;
using Newtonsoft.Json.Linq;
var systemTextFormatter = Microsoft.DotNet.Interactive.Formatting.Formatter.GetPreferredFormatterFor(typeof(System.Text.Json.JsonDocument), "text/html");
Formatter.Register<JObject>(
    t => {
        var systemTextObject = System.Text.Json.JsonDocument.Parse(t.ToString());
        var sw = new StringWriter();
        systemTextFormatter.Format(systemTextObject, sw);
        return sw.ToString();
    }, 
    mimeType: "text/html");
Microsoft.DotNet.Interactive.Formatting.Formatter.SetPreferredMimeTypesFor(typeof(Newtonsoft.Json.Linq.JObject), "text/html");

It works, but I believe that Newtonsoft should be supported out of the box. (Also it took some time for me to come to this solution, I guess other folks also could have some trouble with this)

Please complete the following:

Which version of .NET Interactive are you using? (In a notebook, run the #!about magic command. ): .NET Interactive

© 2020 Microsoft Corporation

Version: 1.0.416502+d1b731772b784b6bb4257dc8d8496d1ab938e534

Library version: 1.0.0-beta.23165.2+d1b731772b784b6bb4257dc8d8496d1ab938e534

Build date: 2023-03-19T08:25:03.2539902Z

https://github.com/dotnet/interactive

Screenshots

image

colombod commented 1 year ago

I think the workaround should become a formatter to the Newtonsoft types, having an extension to handle that could be useful