如何为System.Text.json.jsonserializer设置全球设置默认选项?

发布于 01-19 08:43 字数 2294 浏览 3 评论 0 原文

相反:

JsonSerializerOptions options = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
    // etc.
};
var so = JsonSerializer.Deserialize<SomeObject>(someJsonString, options);

我想做这样的事情:

// This property is a pleasant fiction
JsonSerializer.DefaultSettings = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
    // etc.
};

// This uses my options
var soA = JsonSerializer.Deserialize<SomeObject>(someJsonString); 

// And somewhere else in the same codebase...
// This also uses my options
var soB = JsonSerializer.Deserialize<SomeOtherObject>(someOtherJsonString); 

希望不必为我们最常见的情况传递 JsonSerializerOptions 的实例,并覆盖异常,而不是规则。

此问答中所示a,这是 Json.Net 的一个有用的功能。我查看了文档 对于 System.Text.Json 以及此 GitHub 存储库 对于 . NET 核心。还有这个

.NET Core 3 中似乎没有用于管理 JSON 序列化默认值的类似方法。或者我忽略了它?


Instead of this:

JsonSerializerOptions options = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
    // etc.
};
var so = JsonSerializer.Deserialize<SomeObject>(someJsonString, options);

I would like to do something like this:

// This property is a pleasant fiction
JsonSerializer.DefaultSettings = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
    // etc.
};

// This uses my options
var soA = JsonSerializer.Deserialize<SomeObject>(someJsonString); 

// And somewhere else in the same codebase...
// This also uses my options
var soB = JsonSerializer.Deserialize<SomeOtherObject>(someOtherJsonString); 

The hope is to not have to pass an instance of JsonSerializerOptions for our most common cases, and override for the exception, not the rule.

As indicated in this q & a, this is a useful feature of Json.Net. I looked in the documentation for System.Text.Json as well as this GitHub repo for .NET Core. And this one.

There doesn't seem to be an analog for managing JSON serialization defaults in .NET Core 3. Or am I overlooking it?


如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

谁与争疯 2025-01-26 08:43:38

您可以创建一个扩展方法。 这是一个示例更新 2023-10-27:将代码拉到底部这个答案是为了完整性)

我使用单独的方法而不是必须构建特殊的设置,以便所有设置都将位于一个位置并且易于重用。

public static class DeserializeExtensions
{
    private static JsonSerializerOptions defaultSerializerSettings = new JsonSerializerOptions();
    
    // set this up how you need to!
    private static JsonSerializerOptions featureXSerializerSettings = new JsonSerializerOptions();


    public static T Deserialize<T>(this string json)
    {       
        return JsonSerializer.Deserialize<T>(json, defaultSerializerSettings);
    }
    
    public static T DeserializeCustom<T>(this string json, JsonSerializerOptions settings)
    {
        return JsonSerializer.Deserialize<T>(json, settings);
    }
    
    public static T DeserializeFeatureX<T>(this string json)
    {
        return JsonSerializer.Deserialize<T>(json, featureXSerializerSettings);
    }
}

然后,您可以将其作为字符串(无论是文字还是变量)的方法来调用。

    Car result = @"{""Wheels"": 4, ""Doors"": 2}".DeserializeFeatureX<Car>();

更新于2023年10月27日
我重新审视了这个答案,并意识到示例代码从未包含在此处。我已将其复制到此处,以防链接代码发生问题。它最初针对 .NET Core 3.x,但最后确认是针对 .NET 7。

using System;
using System.Text.Json;
                    
public class Program
{
    public static void Main()
    {
        Console.WriteLine("Hello World");
        
        
        // "json".Deserialize<object>();
        Car result = @"{""Wheels"": 4, ""Doors"": 2}".DeserializeFeatureX<Car>();
        
        Console.WriteLine($"Doors: { result.Doors }, Wheels: { result.Wheels }");
    }
}

public static class DeserializeExtensions
{
    private static JsonSerializerOptions defaultSerializerSettings =
        new JsonSerializerOptions();
    
    // set this up how you need to!
    private static JsonSerializerOptions featureXSerializerSettings =
        new JsonSerializerOptions();


    public static T Deserialize<T>(this string json)
    {       
        return JsonSerializer.Deserialize<T>(json, defaultSerializerSettings);
    }
    
    public static T DeserializeCustom<T>(this string json, JsonSerializerOptions settings)
    {
        return JsonSerializer.Deserialize<T>(json, settings);
    }
    
    public static T DeserializeFeatureX<T>(this string json)
    {
        return JsonSerializer.Deserialize<T>(json, featureXSerializerSettings);
    }
}

public class Car
{
  public int Wheels { get; set; }
  public int Doors { get; set; }
}

You can create an extension method. Here's an example (UPDATE 2023-10-27: Pulled the code to the bottom of this answer for completeness)

I use separate methods vs having to build special settings, so that all the settings will be in a single spot and easily reusable.

public static class DeserializeExtensions
{
    private static JsonSerializerOptions defaultSerializerSettings = new JsonSerializerOptions();
    
    // set this up how you need to!
    private static JsonSerializerOptions featureXSerializerSettings = new JsonSerializerOptions();


    public static T Deserialize<T>(this string json)
    {       
        return JsonSerializer.Deserialize<T>(json, defaultSerializerSettings);
    }
    
    public static T DeserializeCustom<T>(this string json, JsonSerializerOptions settings)
    {
        return JsonSerializer.Deserialize<T>(json, settings);
    }
    
    public static T DeserializeFeatureX<T>(this string json)
    {
        return JsonSerializer.Deserialize<T>(json, featureXSerializerSettings);
    }
}

Then you call it as a method on a string, whether literal or a variable.

    Car result = @"{""Wheels"": 4, ""Doors"": 2}".DeserializeFeatureX<Car>();

Updated 2023-10-27
I revisited this answer and realized that the example code was never included here. I have copied it here in case something happens to the linked code. It was originally targeting .NET Core 3.x but last confirmed with .NET 7.

using System;
using System.Text.Json;
                    
public class Program
{
    public static void Main()
    {
        Console.WriteLine("Hello World");
        
        
        // "json".Deserialize<object>();
        Car result = @"{""Wheels"": 4, ""Doors"": 2}".DeserializeFeatureX<Car>();
        
        Console.WriteLine(
quot;Doors: { result.Doors }, Wheels: { result.Wheels }");
    }
}

public static class DeserializeExtensions
{
    private static JsonSerializerOptions defaultSerializerSettings =
        new JsonSerializerOptions();
    
    // set this up how you need to!
    private static JsonSerializerOptions featureXSerializerSettings =
        new JsonSerializerOptions();


    public static T Deserialize<T>(this string json)
    {       
        return JsonSerializer.Deserialize<T>(json, defaultSerializerSettings);
    }
    
    public static T DeserializeCustom<T>(this string json, JsonSerializerOptions settings)
    {
        return JsonSerializer.Deserialize<T>(json, settings);
    }
    
    public static T DeserializeFeatureX<T>(this string json)
    {
        return JsonSerializer.Deserialize<T>(json, featureXSerializerSettings);
    }
}

public class Car
{
  public int Wheels { get; set; }
  public int Doors { get; set; }
}

寂寞陪衬 2025-01-26 08:43:38

这似乎对我有用,在 StartUp.ConfigureServices 中:

services.AddControllers().AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
        options.JsonSerializerOptions.PropertyNamingPolicy=JsonNamingPolicy.CamelCase;
    });

This seemed to work for me, in StartUp.ConfigureServices:

services.AddControllers().AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
        options.JsonSerializerOptions.PropertyNamingPolicy=JsonNamingPolicy.CamelCase;
    });
七禾 2025-01-26 08:43:38

不, JsonSerializerOptions 不会公开 默认选项。如果您使用特定的 Web 框架,可能有一种方法可以通过它指定(反)序列化设置。否则,我建议创建您自己的便捷方法。

另请参阅此未决问题

No, JsonSerializerOptions does not expose the default options. If you are using a particular web framework there may be a way to specify (de-)serialization settings through that. Otherwise, I suggest creating your own convenience methods.

See also this open issue.

手长情犹 2025-01-26 08:43:38

.NET Core 3.1 的 JsonSerializer 中未公开默认选项。不过,截至 2019 年 12 月,这已添加到路线图中对于 5.0。

.NET 5.0 预计于 2020 年 11 月发布。但不能保证这个特定问题将在任何特定时间得到解决。除了等待之外,这些答案还建议了解决方法:

此外,受 @ps2goat 答案的启发,我打包了方便的扩展方法将它们放在 nuget.orggithub

The default options are not exposed in JsonSerializer for .NET Core 3.1. However, as of December, 2019 this has been added to the road map for 5.0.

The release of .NET 5.0 is expected November, 2020. But there's no guarantee this particular issue will be addressed at any particular time. Other than waiting, these answers suggest workarounds:

Also, I packaged my convenience extension methods, inspired by @ps2goat's answer and put them on nuget.org and github:

梦中的蝴蝶 2025-01-26 08:43:38

a workaround> workaround> ://github.com/andre-ss6“ rel =“ nofollow noreferrer”> andre-ss6 如下:

((JsonSerializerOptions)typeof(JsonSerializerOptions)
    .GetField("s_defaultOptions", 
        System.Reflection.BindingFlags.Static |
        System.Reflection.BindingFlags.NonPublic).GetValue(null))
    .PropertyNameCaseInsensitive = true;

update [2023-02-17] :但是有关net7 href =“ https://stackoverflow.com/a/74741382/1011722”>此答案。

A workaround has been proposed by GitHub user andre-ss6 as follows:

((JsonSerializerOptions)typeof(JsonSerializerOptions)
    .GetField("s_defaultOptions", 
        System.Reflection.BindingFlags.Static |
        System.Reflection.BindingFlags.NonPublic).GetValue(null))
    .PropertyNameCaseInsensitive = true;

Update [2023-02-17]: but for NET7 see this answer.

会发光的星星闪亮亮i 2025-01-26 08:43:38

使用.NET 8预发行,甚至包括蛇盒!

.ConfigureHttpJsonOptions(options => {
          options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower;
})

Using .NET 8 prerelease and it even includes snake case!

.ConfigureHttpJsonOptions(options => {
          options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower;
})
风向决定发型 2025-01-26 08:43:38

我寻找一种解决方案来使用源生成的上下文作为默认序列化器,但默认选项仍然是只读的。

我将其留在这里,以防对其他人有帮助: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/source- Generation?pivots=dotnet-8-0#source- Generation-support- in-aspnet-core

那里的解决方案如下所示:

[JsonSerializable(typeof(WeatherForecast[]))]
internal partial class MyJsonContext : JsonSerializerContext { }
var serializerOptions = new JsonSerializerOptions
{
    TypeInfoResolver = MyJsonContext.Default;
};

services.AddControllers().AddJsonOptions(
    static options =>
        options.JsonSerializerOptions.TypeInfoResolverChain.Add(MyJsonContext.Default));

I looked for a solution to use my source generated context as the default serializer, but the default options are still read-only.

I'll just leave this here in case it helps someone else: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/source-generation?pivots=dotnet-8-0#source-generation-support-in-aspnet-core

The solution there looks like this:

[JsonSerializable(typeof(WeatherForecast[]))]
internal partial class MyJsonContext : JsonSerializerContext { }
var serializerOptions = new JsonSerializerOptions
{
    TypeInfoResolver = MyJsonContext.Default;
};

services.AddControllers().AddJsonOptions(
    static options =>
        options.JsonSerializerOptions.TypeInfoResolverChain.Add(MyJsonContext.Default));
倒带 2025-01-26 08:43:38

一些田地已成为自动企业的开始.NET7。因此,无法像早期答案那样更改它。

新方法是直接更改私有字段:

public static void SetIgnoreNulls() => typeof(JsonSerializerOptions).GetRuntimeFields()
        .Single(f => f.Name == "_defaultIgnoreCondition")
        .SetValue(JsonSerializerOptions.Default, JsonIgnoreCondition.WhenWritingNull);

为什么 getruntimefields()。单(),而不仅仅是 getruntimefield(%name%)?答案在这里: https://github.com/dotnet/runtime/runtime/15643

Some fields has became auto-properties starting .NET7. So there is no way to change it as in earlier answers.

New approach is to change the private fields directly:

public static void SetIgnoreNulls() => typeof(JsonSerializerOptions).GetRuntimeFields()
        .Single(f => f.Name == "_defaultIgnoreCondition")
        .SetValue(JsonSerializerOptions.Default, JsonIgnoreCondition.WhenWritingNull);

Why GetRuntimeFields().Single() and not just GetRuntimeField(%name%)? Answer is here: https://github.com/dotnet/runtime/issues/15643

余生共白头 2025-01-26 08:43:38

如果还需要将自定义转换器添加到默认的 JsonSerializerOptions (System.Text.Json >= 7.0.0) - 不使用控制器 - 可以使用以下技巧:

var jsonConverterList = new List<JsonConverter>
{
    new YourCustomConverter1(),
    new YourCustomConverter2()
};

Type type = AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(assembly => assembly.GetTypes())
    .SingleOrDefault(t => t.FullName == "System.Text.Json.JsonSerializerOptions+ConverterList");
object[] paramValues = new object[] { JsonSerializerOptions.Default, jsonConverterList };
var converterList = type!.GetConstructors()[0].Invoke(paramValues) as IList<JsonConverter>;
typeof(JsonSerializerOptions).GetRuntimeFields().Single(f => f.Name == "_converters")
    .SetValue(JsonSerializerOptions.Default, converterList);

属性 JsonSerializerOptions.Default.Converters 不允许添加项目,因为它是不可变的,因此这个技巧完全取代了转换器列表。由于 ConverterList 是一个私有密封类,调用其构造函数需要反射。

In case one also needs to add custom converters to the default JsonSerializerOptions (System.Text.Json >= 7.0.0) - without the use of controllers - one can use the following trick:

var jsonConverterList = new List<JsonConverter>
{
    new YourCustomConverter1(),
    new YourCustomConverter2()
};

Type type = AppDomain.CurrentDomain.GetAssemblies()
    .SelectMany(assembly => assembly.GetTypes())
    .SingleOrDefault(t => t.FullName == "System.Text.Json.JsonSerializerOptions+ConverterList");
object[] paramValues = new object[] { JsonSerializerOptions.Default, jsonConverterList };
var converterList = type!.GetConstructors()[0].Invoke(paramValues) as IList<JsonConverter>;
typeof(JsonSerializerOptions).GetRuntimeFields().Single(f => f.Name == "_converters")
    .SetValue(JsonSerializerOptions.Default, converterList);

The property JsonSerializerOptions.Default.Converters does not allow adding items, as is is immutable, therefore this trick replaces the converterList alltogether. And since ConverterList is a private sealed class invoking its constructor requires reflection.

小嗲 2025-01-26 08:43:38

正如 @elijah 评论的那样,注入 IOptions jsonOptions 对我有用。然后我就可以使用 JsonSerializerOptions 属性。我注意到这与我在 Program.cs 文件中使用 AddJsonOptions() 配置的内容没有区别。

As @elijah commented, injecting IOptions<JsonOptions> jsonOptions worked for me. I was then able to use the JsonSerializerOptions property. I noticed no differences between this and what I had configured using AddJsonOptions() in my Program.cs file.

遮云壑 2025-01-26 08:43:38

对于 ASP.NET Core 7.0+:

builder.Services.ConfigureHttpJsonOptions(options => {
    options.SerializerOptions.PropertyNameCaseInsensitive = true;
    options.SerializerOptions.WriteIndented = true;
    options.SerializerOptions.AllowTrailingCommas = true;
    options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
    options.SerializerOptions.ReferenceHandler =ReferenceHandler.IgnoreCycles;
});

方法 HttpJsonServiceExtensions.ConfigureHttpJsonOptions()

配置使用 Microsoft.AspNetCore.Http.HttpRequestJsonExtensions.ReadFromJsonAsyncMicrosoft.AspNetCore.Http.HttpResponseJsonExtensions.WriteAsJsonAsync JsonOptions 使用来自 JsonSerializerDefaults.Web 的默认值。


此方法可从 ASP.NET Core 7.0

For ASP.NET Core 7.0+:

builder.Services.ConfigureHttpJsonOptions(options => {
    options.SerializerOptions.PropertyNameCaseInsensitive = true;
    options.SerializerOptions.WriteIndented = true;
    options.SerializerOptions.AllowTrailingCommas = true;
    options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
    options.SerializerOptions.ReferenceHandler =ReferenceHandler.IgnoreCycles;
});

The method HttpJsonServiceExtensions.ConfigureHttpJsonOptions():

Configures options used for reading and writing JSON when using Microsoft.AspNetCore.Http.HttpRequestJsonExtensions.ReadFromJsonAsync and Microsoft.AspNetCore.Http.HttpResponseJsonExtensions.WriteAsJsonAsync. JsonOptions uses default values from JsonSerializerDefaults.Web.

This method is available starting from ASP.NET Core 7.0.

暖风昔人 2025-01-26 08:43:38

我必须在HTTP客户端中使用其他转换器进行枚举。就我而言,避免在每个JSON转换中使用选项,并且由于没有选择默认选项的选项(除非使用上述反射)。我创建了一个转换器,并将其用作枚举上方的属性

public class EnumStringConverter<TEnum> : JsonConverter<TEnum> where TEnum : Enum
{
    public override TEnum Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        string enumString = reader.GetString()!;
        return (TEnum)Enum.Parse(typeof(TEnum), enumString, true);
    }

    public override void Write(Utf8JsonWriter writer, TEnum value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString());
    }
}

[JsonConverter(typeof(EnumStringConverter<MyCoolEnum>))]
public enum MyCoolEnum {A,B,C}

I had to use a different converter for enums in my http client. In my case to avoid using the options in each json conversion, and due to not having the option to change the default options (unless using reflection from above). I created a converter and used it as attribute above the enum

public class EnumStringConverter<TEnum> : JsonConverter<TEnum> where TEnum : Enum
{
    public override TEnum Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        string enumString = reader.GetString()!;
        return (TEnum)Enum.Parse(typeof(TEnum), enumString, true);
    }

    public override void Write(Utf8JsonWriter writer, TEnum value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString());
    }
}

Enum:

[JsonConverter(typeof(EnumStringConverter<MyCoolEnum>))]
public enum MyCoolEnum {A,B,C}
迷离° 2025-01-26 08:43:38

基于 @elijah关于注册 ioptions 的建议,这是一个完整的解决方案,它显示了如何在全球范围内正确配置和使用JSON Serialization选项。

解决方案

首先,在 program.cs 中配置选项:

这是针对

 services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
        options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString;
        options.JsonSerializerOptions.WriteIndented = false;
        options.JsonSerializerOptions.MaxDepth = 18;
        options.JsonSerializerOptions.AllowTrailingCommas = true;
        options.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip;
    });

MINIAMAPI的

    services.Configure<Microsoft.AspNetCore.Http.Json.JsonOptions>(options =>
    {
       options.SerializerOptions.PropertyNameCaseInsensitive = true;
       options.SerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString;
       options.SerializerOptions.WriteIndented = false;
       options.SerializerOptions.MaxDepth = 18;
       options.SerializerOptions.AllowTrailingCommas = true;
       options.SerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip;
    });

MVC,然后在您的服务中注入并使用这些选项。如果您需要在constructor中排放。

public class TestService : ITestService
{
   private readonly JsonSerializerOptions _jsonSerializerOptions;

   public TestService(IOptions<JsonOptions> jsonOptions)
   {
       _jsonSerializerOptions = jsonOptions.Value.SerializerOptions;
   }

   public async Task<ModelDto> DeserializeObjectAsync(MemoryStream ms)
   {
       return await JsonSerializer.DeserializeAsync<ModelDto>(
           ms, 
           _jsonSerializerOptions
       );
   }
}

Based on @Elijah's suggestion about registering IOptions, here's a complete solution that shows how to properly configure and use JSON serialization options globally.

Solution

First, configure the options in Program.cs:

That's for MVC

 services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
        options.JsonSerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString;
        options.JsonSerializerOptions.WriteIndented = false;
        options.JsonSerializerOptions.MaxDepth = 18;
        options.JsonSerializerOptions.AllowTrailingCommas = true;
        options.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip;
    });

That's for miniamApi

    services.Configure<Microsoft.AspNetCore.Http.Json.JsonOptions>(options =>
    {
       options.SerializerOptions.PropertyNameCaseInsensitive = true;
       options.SerializerOptions.NumberHandling = JsonNumberHandling.AllowReadingFromString;
       options.SerializerOptions.WriteIndented = false;
       options.SerializerOptions.MaxDepth = 18;
       options.SerializerOptions.AllowTrailingCommas = true;
       options.SerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip;
    });

Then inject and use these options in your services.If you need you can ovveride in constructor.:

public class TestService : ITestService
{
   private readonly JsonSerializerOptions _jsonSerializerOptions;

   public TestService(IOptions<JsonOptions> jsonOptions)
   {
       _jsonSerializerOptions = jsonOptions.Value.SerializerOptions;
   }

   public async Task<ModelDto> DeserializeObjectAsync(MemoryStream ms)
   {
       return await JsonSerializer.DeserializeAsync<ModelDto>(
           ms, 
           _jsonSerializerOptions
       );
   }
}
脱离于你 2025-01-26 08:43:38

发现这个寻找一些灵感。我们有一个 Web API 可以调用其他一些 API。第三方 API 可能使用驼峰命名法,也可能使用 kebab 命名法。一般来说,每个 API 内部都是一致的,但 API 之间的命名约定会发生变化。我需要在有限的范围内配置选项,但不能污染其他项目。

我最终创建了一个选项对象,这样命名是为了不与设置混淆,特定于每个项目(将可见性设置为内部),通过 DI 呈现,该对象将 JSON 设置作为属性。特定于项目的设置(例如任意 API 如何命名属性)包含在该项目中,并且每个项目负责设置其默认值。

我发现,特别是对于库代码来说,具体并处理传递选项对象比尝试设置完整的应用程序默认值只是为了限制互操作性更好。这也让我可以避免在 DTO 上标记属性名称,因此我可以从顶级 API 序列化 DTO 出站,并且不会有违反 API 级约定的显式 JSON 属性名称。

如果您确实必须支持非典型的特定于属性的名称,则可以对公共未修饰属性使用带有 getter 和 setter 的内部属性来隔离更改。

Found this looking for some inspiration. We have a web API that calls some other APIs. The third-party APIs may use camel casing names, or they may use kebab. Generally, each is internally consistent with itself, but the naming convention changes between APIs. I needed to configure the options in a limited scope but not contaminate other projects.

I ended up making an options object, called such not to confuse with settings, specific to each project (set visibility to internal), surfaced through DI, that had the JSON settings as a property. Project-specific settings, like how an arbitrary API names properties, are contained to that project, and each project is responsible for setting its defaults.

I've found it's better, especially for library code, to be specific and deal with passing around the options object than to try and set up full app defaults only to limit interoperability. This also lets me avoid marking property names on my DTOs, so I can serialize the DTO outbound from my top-level API and not have explicit JSON property names breaking the API-level conventions.

If you do have to support an atypical property-specific name, you can use an internal property with getters and setters to your public undecorated property to isolate the change.

放我走吧 2025-01-26 08:43:38

(如果您切换到使用 Json.NET)

我更喜欢并建议明确并将设置传递给所有调用,但您可以使用 DefaultSettings

JsonConvert.DefaultSettings = () => MySuperJsonSerializerSettings;

进而

var json = JsonConvert.SerializeObject(o1);
var o2 = JsonConvert.DeserializeObject(x);

(If you ever switch to using Json.NET)

I prefer and recommend being explicit and pass settings to all calls, but you can set defaults with DefaultSettings.

JsonConvert.DefaultSettings = () => MySuperJsonSerializerSettings;

and then

var json = JsonConvert.SerializeObject(o1);
var o2 = JsonConvert.DeserializeObject(x);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文