How do you implement System.Text.Json.Serialization.ReferenceHandler.Preserve in a Blazor WebAssemby application

Viewed 5270

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.

2 Answers

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

services.AddMvc().AddJsonOptions(o =>
        {
            o.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;
        });

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.

Related