Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Customise JSON serialisation #4

Open
cocowalla opened this issue Feb 27, 2019 · 5 comments
Open

Customise JSON serialisation #4

cocowalla opened this issue Feb 27, 2019 · 5 comments
Assignees
Labels
enhancement New feature or request

Comments

@cocowalla
Copy link

cocowalla commented Feb 27, 2019

It's possible to customise JSON serialisation at a global level by changing JsonConvert.DefaultSettings, but it would be good to have the option to customise it just for EF Core JSON serialisation by specifying a JsonSerializerSettings, for example to prevent cyclic references from being serialised, configure null handling, or to add type information to the serialised JSON to support interfaces:


var jsonSettings = new JsonSerializerSettings
{
    NullValueHandling = NullValueHandling.Ignore,
     ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
    TypeNameHandling = TypeNameHandling.Objects,
    TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple
};

var json = JsonConvert.SerializeObject(obj, jsonSettings);
var obj = JsonConvert.DeserializeObject<T>>(json, jsonSettings);

At it's most basic, this could be implemented as a global setting by adding a static JsonSerializerSettings in this library (or a configuration class that composes it). I imagine a global setting would be what most people would want.

Alternatively (or additionally), the HasJsonValueConversion extension method could have an optional JsonSerializerSettings argument added to it. Not sure if there would really be a need to configure it for each property though.

@ghost
Copy link

ghost commented Feb 27, 2019

I'd like this feature too. I've implemented the most basic solution in a fork, adding a static JsonSerializerSettings exposed from JsonHelper and making sure both the converter and comparer use the settings.

In my application, I added an extension method for DbContextOptionsBuilder to modify the settings in my Startup.cs without referring to the JsonHelper directly.

public static class DbContextOptionsBuilderExtensions
{
    public static DbContextOptionsBuilder AddJsonConverterSettings(this DbContextOptionsBuilder dbContextOptions, Action<JsonSerializerSettings> setupAction)
    {
        setupAction(JsonHelper.SerializerSettings);
    
        return dbContextOptions;
    }
}

And use it like so:

services.AddDbContext<ApplicationDbContext>(options =>
{
    options.UseSqlServer(Configuration.GetConnectionString("Application"));

    options.AddJsonConverterSettings(settings =>
    {
        settings.ContractResolver = new DefaultContractResolver
        {
            NamingStrategy = new CamelCaseNamingStrategy()
        };
    });
});

I suppose that extension method could also be included in the library instead and then JsonHelper could remain internal.

@AlexEngblom
Copy link
Member

@cocowalla this seems useful suggestion. I suppose that global settings should be sufficient for usual needs and pretty straightforward to implement.

@webwizgordon this looks viable to me, as well as the consideration to add required extensions in library for less wiring. I wonder if it would be better to pass configuration settings inside the ApplicationDbContext setup though. For example if the context implementation is shared between multiple applications.

@AlexEngblom AlexEngblom added the enhancement New feature or request label Mar 7, 2019
@AlexEngblom AlexEngblom self-assigned this Mar 7, 2019
@ghost
Copy link

ghost commented Mar 11, 2019

You might also want to consider having a separate instance of JsonSerializerSettings per DbContext type instead of a single static instance shared between all DbContext types. Someone could conceivably have multiple types of DbContexts and may want different JsonSerializerSettings for each for some reason.

@lvmajor
Copy link

lvmajor commented Jan 15, 2020

Is there any update about this? That would be really useful !

@JasonLandbridge
Copy link

For those looking for a workaround, add this extension method to your project:

    /// <summary>
    /// Extensions for <see cref="T:Microsoft.EntityFrameworkCore.Metadata.Builders.PropertyBuilder" />.
    /// </summary>
    public static class PropertyBuilderExtensions
    {
        /// <summary>Serializes field as JSON blob in database.</summary>
        public static PropertyBuilder<T> HasJsonValueConversion<T>(
            this PropertyBuilder<T> propertyBuilder)
            where T : class
        {
            propertyBuilder.HasConversion(
                v => JsonConvert.SerializeObject(v, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore}),
                v => JsonConvert.DeserializeObject<T>(v, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore }));

            return propertyBuilder;
        }
    }

Here you can change your serializerSettings and then use it per property like this:

builder
    .Property(x => x.MetaData)
    .HasJsonValueConversion();

This method also allows you to change on a per-context basis, just make a second extension method with your unique serializer settings, or tweak the HasJsonValueConversion() method to pass a new JsonSerializerSettings() .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants