Azure-webjobs-sdk: Customize JSON serialization (ReferenceLoopHandling)

Created on 2 Jun 2017  路  3Comments  路  Source: Azure/azure-webjobs-sdk

Looking through the docs and source, I wasn't able to identify a way to handle reference loops when the SDK JSON serializes an entity I fetched using Entity Framework with an [InversePropety] defined (thus having a reference loop between entities).

This is currently an issue when I fetch an entity using Entity Framework that I would like to serialize into a queue to be processed by another job.

```c#
public static void ProcessRoundEvents(
[QueueTrigger("round-event-queue")] RoundEvent roundEvent,
[Queue("notification-queue")] ICollector notificationQueue,
TextWriter log)
{
using (var context = new MyContext())
{
var round = context.Rounds.Find(roundEvent.RoundId);

    var notification = new Notification()
    {
        Subject = subject,
        Body = body,
        User = u
    };
    notificationQueue.Add(notification); // Throws: Newtonsoft.Json.JsonSerializationException: 'Self referencing loop detected for property 'User' with type 'System.Data.Entity.DynamicProxies.User_309B62C34D1D6A13D9F8F10F144F9CC97D0D3B59D11415279D19D5A9F9AFB777'. Path 'User.NotificationRegistrations[0]'.'  
}

}

I am able to work around this when I enqueue items manually (from the frontend) by setting the `ReferenceLoopHandling` property on `JsonSerializerSettings` when calling `JsonConvert.SerializeObject` such as:

```c#
var messageAsJson = JsonConvert.SerializeObject(objectToSerialize, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
var message = new CloudQueueMessage(messageAsJson);

In WebApi, it's common to set this globally on the HttpConfiguration such as
```c#
...
var config = new HttpConfiguration();

var jsonFormatter = config.Formatters.JsonFormatter;
// Fix "Self referencing loop" - http://stackoverflow.com/questions/7397207/json-net-error-self-referencing-loop-detected-for-type
jsonFormatter.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
...
```

It seems like being able to do something similar on var config = JobHostConfiguration() would be great.

As a workaround, I currently just add the UserId to my Notification class that is enqueued, which is probably a better approach, but it does require other jobs down stream to have to fetch the entity from the database themselves.

improvement

Most helpful comment

This needs to be configurable.

All 3 comments

This needs to be configurable.

I think I am having a similar problem, I need to change the default json serialisation settings to add a custom JsonConverter, as I cant I have to add [JsonConverter(typeof(SnowflakeConverter))] to all properties instead of adding it to just the serilizer :/

I had the same problem in an Azure Function v2 and could solve it by adding a startup class

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using System;

[assembly: FunctionsStartup(typeof(TestFunctions.Startup))]
namespace TestFunctions
{
    class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            JsonConvert.DefaultSettings = () => new JsonSerializerSettings
            {
                Formatting = Formatting.Indented,
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore
            };
        }
    }
}
Was this page helpful?
0 / 5 - 0 ratings