9

It's my understanding that you can use this setting to get around the issue of getting the following error when you have circular references defined in your object model:

JsonException: A possible object cycle was detected which is not supported. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32.

However I have not been able to implement it successfully to get it to work. If anyone can provide detailed instructions on what needs to be done it would be much appreciated!

I thought about switching the application to using Newtonsoft.JSON but from what I've read this is not doable in a Blazor WebAssembly application?

Update 12/12/2020

The closest articles I had found in trying to figure out how to implement ReferenceHandler.Preserve were these:

https://github.com/dotnet/runtime/issues/42584

https://github.com/dotnet/aspnetcore/issues/28286

Based on these articles I tried implementing the following solutions, neither of which worked...

First attempt I implemented the following code in the Startup.cs class in my Server project:

services.AddControllersWithViews().AddJsonOptions(options =>
            {
                options.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.Preserve;
            });

Second attempt I implemented the following code in the Startup.cs class in my Server project:

services.AddControllersWithViews(options =>
            {
                options.OutputFormatters.RemoveType<SystemTextJsonOutputFormatter>();
                options.OutputFormatters.Add(new SystemTextJsonOutputFormatter(new JsonSerializerOptions(JsonSerializerDefaults.Web)
                {
                    ReferenceHandler = ReferenceHandler.Preserve
                }));
            });

Update 12/12/2020 11:12 AM CST

After changing my Server project to target .NET 5 and trying both code options from above i now get the following type of error on EVERY page in my application:

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: The JSON value could not be converted to BusinessManager.Shared.Models.EmploymentBenefit[]. Path: $ | LineNumber: 0 | BytePositionInLine: 1.

Steps To Reproduce Original Problem

Create a new Blazor WebAssembly application

In the Shared project define a parent class that has a collection of child objects as follows:

public virtual List<Child> Children{ get; set; } = new List<Child>();

In the Child class define a property that references its parent as follows:

public virtual Parent Parent{ get; set; }

Then, I use entity framework to generate the database objects. Create a web api function that returns the parent and its child objects as such:

[HttpGet("{id}")]
        public async Task<IActionResult> Get(Guid id)
        {
            var returnValue = await db.Parents
                .Include(aa => aa.Children)
                .FirstOrDefaultAsync(aa => aa.ParentId== id);
            return Ok(returnValue);
        }

And then try to render the parent and child collection on a page by calling this web api function.

scooter
  • 283
  • 4
  • 10
  • See the doc pages [Proposal: Add mechanism to handle circular references when serializing #30820](https://github.com/dotnet/runtime/issues/30820) and [Preserve object references and handle loops](https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to?pivots=dotnet-5-0#preserve-object-references-and-handle-loops) and [How to preserve references and handle circular references with System.Text.Json](https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-preserve-references?pivots=dotnet-5-0). – dbc Dec 12 '20 at 05:51
  • Beyond that, you wrote, *However I have not been able to implement it successfully to get it to work.* - then can you share a [mcve] showing what did not work? From [ask]: *Help others reproduce the problem... if your problem is with code you've written, you should include some... Include just enough code to allow others to reproduce the problem.* – dbc Dec 12 '20 at 05:53
  • Here is an example of using `ReferenceHandler.Preserve`: https://dotnetfiddle.net/t2EkHR. **Note that `ReferenceHandler.Preserve` only works in .Net 5 or later.** To diagnose the problem you mention when you wrote *I have not been able to implement it successfully to get it to work* we need to see a [mcve] with the code you have written that does not work. – dbc Dec 12 '20 at 16:32
  • Updated my post with code examples. I'm wondering if the .Net 5 or later aspect isn't at least part of the problem with a Blazor WebAssembly application as I'm not seeing you can use .Net 5 with Blazor WebAssembly although I am finding all the various versions of frameworks a little confusing and hard to keep straight. However, the code compiles fine with my changes in place. I am referencing System.Net.Http.Json version 5.0.0 in my server project. My Client project targets .NET Standard 2.1 and my Server project targets .NET Core 3.1 – scooter Dec 12 '20 at 16:50
  • Might you [edit] your question to include code showing how you are invoking the serializer? Incidentally the fiddle https://dotnetfiddle.net/t2EkHR has some code that prints the current .Net version in runtime, you might be able to use that to confirm you are running under .Net 5. – dbc Dec 12 '20 at 16:53
  • I see i have an option to change my Server project to target .NET 5.0 so i'm going to see if that fixes anything. – scooter Dec 12 '20 at 16:55
  • Still haven't been able to get it to work. I've updated original post with new information. – scooter Dec 12 '20 at 19:55
  • Not sure then. If you are using Entity Framework, I know that Json.NET's `PreserveReferencesHandling` functionality does not work with dynamic proxies, one needs to set `Configuration.ProxyCreationEnabled = false;` e,g, as shown [here](https://stackoverflow.com/a/19468282/3744182). I'm not familiar with Blazor WebAssembies but maybe something similar is going on here? – dbc Dec 12 '20 at 20:04
  • 1
    Your second serialization code works, but it creates json with fields like $id, $values and $ref, which System.Text.Json is not able to deserialize back. – Marek Toman Jan 22 '21 at 00:01

2 Answers2

0

Here's what I did with mine. In Startup.cs add this

services.AddMvc().AddJsonOptions(o =>
        {
            o.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;
        });
MaJo
  • 55
  • 5
0

After changing my Server project to target .NET 5 and trying both code options from above i now get the following type of error on EVERY page in my application:

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: The JSON value could not be converted to BusinessManager.Shared.Models.EmploymentBenefit[]. Path: $ | LineNumber: 0 | BytePositionInLine: 1.

Are you enabling ReferenceHandler.Preserve in your client side as well? Otherwise the JsonSerializer in the client won't be aware of the metadata.

Jozkee
  • 57
  • 1
  • 13