Sage.JsonConverters 1.0.0.3

dotnet add package Sage.JsonConverters --version 1.0.0.3
                    
NuGet\Install-Package Sage.JsonConverters -Version 1.0.0.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Sage.JsonConverters" Version="1.0.0.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Sage.JsonConverters" Version="1.0.0.3" />
                    
Directory.Packages.props
<PackageReference Include="Sage.JsonConverters" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Sage.JsonConverters --version 1.0.0.3
                    
#r "nuget: Sage.JsonConverters, 1.0.0.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Sage.JsonConverters@1.0.0.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Sage.JsonConverters&version=1.0.0.3
                    
Install as a Cake Addin
#tool nuget:?package=Sage.JsonConverters&version=1.0.0.3
                    
Install as a Cake Tool

Sage.JsonConverters

简介

Sage.JsonConverters 是一个专为处理不规范第三方API数据而设计的安全JSON转换器库。该库提供了一系列绝对不会抛出异常的JSON转换器,能够安全地处理各种格式不一致的数据,确保程序的稳定性和可靠性。

特性

  • 绝对安全:所有转换器都不会抛出异常,对于无效数据返回默认值或null
  • 多类型支持:支持数字、字符串、布尔值、日期时间、对象等多种数据类型的自动转换
  • 灵活转换:支持字符串数字、多种布尔值表示形式、多种日期格式等
  • 可空类型支持:提供可空版本的转换器,便于区分"未设置"和"默认值"状态
  • 预配置选项:提供多种预配置的JsonSerializerOptions,适用于不同场景
  • 高性能:使用单例模式避免重复创建转换器实例
  • 完全兼容 AOT 编译:支持原生AOT编译和源生成,提升性能
  • 通用对象转换:SafeObjectConverter,专门处理第三方API的不一致格式(数组 集合)
  • 空数组处理:智能处理空数组[]转换为null的场景

安装

dotnet add package Sage.JsonConverters

使用示例

基本使用

使用预配置的安全选项
using Sage.JsonConverters;
using System.Text.Json;

// 使用包含所有安全转换器的配置(推荐用于生产环境)
var options = SafeJsonConverters.CreateSafeOptions();

// 处理不规范的JSON数据
string json = """
{
    "id": "123",           // 字符串数字
    "count": null,         // null值
    "price": "99.99",      // 字符串价格
    "isActive": "true",    // 字符串布尔值
    "score": "",           // 空字符串
    "date": "2023-12-20 14:30:00"
}
""";

var data = JsonSerializer.Deserialize<ProductData>(json, options);
// 所有字段都能正确转换,不会抛出异常
定义数据模型
public class ProductData
{
    public int Id { get; set; }           // 从字符串"123"转换为123
    public int Count { get; set; }        // 从null转换为0
    public decimal Price { get; set; }    // 从字符串"99.99"转换为99.99m
    public bool IsActive { get; set; }    // 从字符串"true"转换为true
    public int Score { get; set; }        // 从空字符串转换为0
    public DateTime Date { get; set; }    // 从字符串转换为DateTime
}

不同场景的预配置选项

1. 第三方API集成(推荐使用可空类型)
// 使用可空转换器,更容易区分"未设置"状态
var options = SafeJsonConverters.CreateNullableOptions();

public class ApiResponse
{
    public int? UserId { get; set; }      // null表示未设置
    public decimal? Balance { get; set; }  // null表示未知余额
    public bool? IsVerified { get; set; }  // null表示未验证
    public DateTime? LastLogin { get; set; } // null表示从未登录
}
2. 财务系统(高精度计算)
// 使用decimal确保精度的财务配置
var options = SafeJsonConverters.CreateFinancialOptions();

public class FinancialData
{
    public decimal? Amount { get; set; }     // 使用decimal确保精度
    public decimal? Tax { get; set; }        // 税费计算
    public int? TransactionId { get; set; }  // 交易ID
    public DateTime? TransactionDate { get; set; } // 交易日期
}
3. 高性能场景(仅数值转换)
// 轻量级配置,只包含数值转换器
var options = SafeJsonConverters.CreateNumberOnlyOptions();

public class MetricsData
{
    public int RequestCount { get; set; }
    public long ResponseTime { get; set; }
    public decimal SuccessRate { get; set; }
}
4. 源生成场景(AOT兼容)
// 使用源生成的JsonSerializerContext
[JsonSerializable(typeof(ApiResponse))]
public partial class MyJsonContext : JsonSerializerContext { }

// 创建支持源生成的安全配置
var context = MyJsonContext.Default;
var options = SafeJsonConverters.CreateSafeOptionsForSourceGeneration(context);

// 在AOT场景下安全反序列化
var response = JsonSerializer.Deserialize<ApiResponse>(json, options);
5. 简单配置数据
// 基本类型转换器配置
var options = SafeJsonConverters.CreateBasicOptions();

public class ConfigData
{
    public int? Port { get; set; }
    public long? MaxMemory { get; set; }
    public decimal? Timeout { get; set; }
    public bool? EnableLogging { get; set; }
}

使用通用对象转换器处理复杂场景

处理第三方API的不一致格式
// 第三方API有时返回对象,有时返回空数组
string inconsistentJson1 = """
{
    "user": {
        "id": 123,
        "name": "张三"
    }
}
""";

string inconsistentJson2 = """
{
    "user": []
}
""";

// 使用SafeObjectConverter处理
public class ApiResponse
{
    [JsonConverter(typeof(SafeJsonConverters.SafeObjectConverter<User>))]
    public User? User { get; set; }
}

public class User
{
    public int Id { get; set; }
    public string? Name { get; set; }
}

var options = SafeJsonConverters.CreateSafeOptions();

// 两种格式都能正确处理
var response1 = JsonSerializer.Deserialize<ApiResponse>(inconsistentJson1, options);
// response1.User 包含用户数据

var response2 = JsonSerializer.Deserialize<ApiResponse>(inconsistentJson2, options);
// response2.User 为 null(空数组被转换为null)
AOT场景下的对象转换
// 在AOT场景下使用SafeObjectConverter
[JsonSerializable(typeof(User))]
public partial class UserJsonContext : JsonSerializerContext { }

// 创建支持AOT的对象转换器
var userTypeInfo = UserJsonContext.Default.User;
var objectConverter = new SafeJsonConverters.SafeObjectConverter<User>(userTypeInfo);

// 手动配置转换器
var options = new JsonSerializerOptions();
options.Converters.Add(objectConverter);

使用特性标注的自动转换

using System.Text.Json.Serialization;
using Sage.JsonConverters;

// 在属性上直接使用转换器特性
public class ProductInfo
{
    [JsonConverter(typeof(SafeJsonConverters.SafeIntConverter))]
    public int ProductId { get; set; }
    
    [JsonConverter(typeof(SafeJsonConverters.SafeNullableDecimalConverter))]
    public decimal? Price { get; set; }
    
    [JsonConverter(typeof(SafeJsonConverters.SafeNullableBoolConverter))]
    public bool? IsAvailable { get; set; }
    
    [JsonConverter(typeof(SafeJsonConverters.SafeNullableDateTimeConverter))]
    public DateTime? CreatedDate { get; set; }
    
    // 使用SafeObjectConverter处理可能为空数组的对象
    [JsonConverter(typeof(SafeJsonConverters.SafeObjectConverter<ProductDetails>))]
    public ProductDetails? Details { get; set; }
    
    // 普通属性不需要特殊处理
    public string? Name { get; set; }
    public string? Description { get; set; }
}

public class ProductDetails
{
    public string? Category { get; set; }
    public string? Brand { get; set; }
    public int? Weight { get; set; }
}

// 使用时不需要特殊配置
string json = """
{
    "productId": "12345",
    "price": "99.99",
    "isAvailable": "true",
    "createdDate": "2023-12-20 14:30:00",
    "details": {
        "category": "电子产品",
        "brand": "示例品牌",
        "weight": "500"
    },
    "name": "示例产品",
    "description": null
}
""";

// 处理空数组的情况
string jsonWithEmptyArray = """
{
    "productId": "12345",
    "price": "99.99",
    "isAvailable": "true",
    "createdDate": "2023-12-20 14:30:00",
    "details": [],
    "name": "示例产品",
    "description": null
}
""";

// 直接反序列化,标注的属性会自动使用安全转换器
var product1 = JsonSerializer.Deserialize<ProductInfo>(json);
// product1.Details 包含详细信息

var product2 = JsonSerializer.Deserialize<ProductInfo>(jsonWithEmptyArray);
// product2.Details 为 null(空数组被安全转换为null)
源生成场景下的SafeObjectConverter特性标注

当使用源生成(AOT兼容)时,SafeObjectConverter的特性标注需要特殊处理:

// 1. 定义JsonSerializerContext
[JsonSerializable(typeof(ProductInfo))]
[JsonSerializable(typeof(ProductDetails))]  // 必须包含嵌套类型
public partial class ProductJsonContext : JsonSerializerContext { }

// 2. 数据模型定义(与上面相同)
public class ProductInfo
{
    [JsonConverter(typeof(SafeJsonConverters.SafeIntConverter))]
    public int ProductId { get; set; }
    
    [JsonConverter(typeof(SafeJsonConverters.SafeNullableDecimalConverter))]
    public decimal? Price { get; set; }
    
    // 在源生成场景下,SafeObjectConverter需要特殊处理
    // 注意:特性标注在源生成中可能不完全支持,建议使用手动配置
    [JsonConverter(typeof(SafeJsonConverters.SafeObjectConverter<ProductDetails>))]
    public ProductDetails? Details { get; set; }
    
    public string? Name { get; set; }
}

public class ProductDetails
{
    public string? Category { get; set; }
    public string? Brand { get; set; }
    public int? Weight { get; set; }
}

// 3. 推荐的源生成使用方式(手动配置转换器)
var context = ProductJsonContext.Default;
var options = SafeJsonConverters.CreateSafeOptionsForSourceGeneration(context);

// 为SafeObjectConverter添加JsonTypeInfo支持
var detailsTypeInfo = ProductJsonContext.Default.ProductDetails;
var objectConverter = new SafeJsonConverters.SafeObjectConverter<ProductDetails>(detailsTypeInfo);
options.Converters.Add(objectConverter);

// 使用配置进行反序列化
var product = JsonSerializer.Deserialize<ProductInfo>(json, options);

重要说明:

  • 在源生成场景下,推荐使用手动配置而非特性标注
  • 必须在JsonSerializerContext中包含所有相关类型
  • SafeObjectConverter需要JsonTypeInfo参数以支持AOT

手动配置转换器

// 自定义配置JsonSerializerOptions
var options = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true,
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};

// 添加特定的转换器
options.Converters.Add(SafeJsonConverters.NullableInt);
options.Converters.Add(SafeJsonConverters.NullableDecimal);
options.Converters.Add(SafeJsonConverters.NullableBool);
options.Converters.Add(SafeJsonConverters.NullableDateTime);

支持的数据类型和转换规则

整数转换 (int/int?)
  • 数字:直接转换,处理溢出
  • 字符串数字:"123" → 123
  • 空字符串/null:转换为0(可空版本返回null)
  • 无效格式:返回0(可空版本返回null)
长整数转换 (long/long?)
  • 支持64位整数范围
  • 转换规则与int类似
浮点数转换 (double/double?)
  • 数字:直接转换
  • 字符串数字:"99.99" → 99.99
  • 特殊值:处理NaN、Infinity等
  • 使用InvariantCulture:确保跨文化兼容性
高精度数值转换 (decimal/decimal?)
  • 推荐用于财务计算:确保精度不丢失
  • 字符串转换:"123.456789" → 123.456789m
  • 货币格式支持:处理各种货币表示
布尔值转换 (bool/bool?)
  • 标准布尔值:true/false
  • 数字:非零为true,0为false
  • 字符串:支持多种格式
    • "true"/"false"
    • "yes"/"no"
    • "on"/"off"
    • "y"/"n"
    • "1"/"0"
  • 大小写不敏感
日期时间转换 (DateTime/DateTime?)

支持多种日期格式:

  • ISO 8601:2023-12-20T14:30:00Z
  • 标准格式:2023-12-20 14:30:00
  • 仅日期:2023-12-20
  • 美式格式:12/20/2023
  • 欧式格式:20/12/2023
  • 中文格式:2023/12/20
通用对象转换 (SafeObjectConverter)
  • 正常对象:{} → 正常反序列化
  • 空数组:[] → null(可配置)
  • null值:null → null
  • 字符串/其他类型:安全处理,返回null
  • AOT支持:可传入JsonTypeInfo实现AOT兼容
  • 异常安全:绝对不会抛出异常

在ASP.NET Core中使用

// Program.cs
using Sage.JsonConverters;

var builder = WebApplication.CreateBuilder(args);

// 配置JSON选项
builder.Services.ConfigureHttpJsonOptions(options =>
{
    var safeOptions = SafeJsonConverters.CreateSafeOptions();
    options.SerializerOptions.Converters.Clear();
    
    foreach (var converter in safeOptions.Converters)
    {
        options.SerializerOptions.Converters.Add(converter);
    }
    
    options.SerializerOptions.PropertyNameCaseInsensitive = true;
    options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
});

var app = builder.Build();

处理复杂的第三方API响应

// 第三方API返回的不规范JSON
string apiResponse = """
{
    "user_id": "12345",
    "balance": null,
    "is_premium": "1",
    "last_login": "",
    "settings": {
        "notifications": "true",
        "theme": "dark",
        "timeout": "30"
    }
}
""";

var options = SafeJsonConverters.CreateNullableOptions();
var userData = JsonSerializer.Deserialize<UserData>(apiResponse, options);

public class UserData
{
    public int? UserId { get; set; }        // 从"12345"转换为12345
    public decimal? Balance { get; set; }   // null保持为null
    public bool? IsPremium { get; set; }    // 从"1"转换为true
    public DateTime? LastLogin { get; set; } // 空字符串转换为null
    public UserSettings? Settings { get; set; }
}

public class UserSettings
{
    public bool? Notifications { get; set; } // 从"true"转换为true
    public string? Theme { get; set; }       // 字符串保持不变
    public int? Timeout { get; set; }        // 从"30"转换为30
}

最佳实践

  1. 选择合适的配置

    • 生产环境推荐使用 CreateSafeOptions()
    • 第三方API集成推荐使用 CreateNullableOptions()
    • 财务系统推荐使用 CreateFinancialOptions()
    • AOT场景推荐使用 CreateSafeOptionsForSourceGeneration()
  2. 数据验证:虽然转换器不会抛出异常,但仍建议在业务逻辑中验证关键数据

  3. 性能优化:转换器使用单例模式,可以安全地重复使用配置选项

  4. 错误处理:对于关键业务数据,建议使用可空版本的转换器以便区分"未设置"状态

  5. 测试:在集成第三方API时,使用各种边界情况测试转换器的行为

  6. 对象转换:对于可能返回空数组的第三方API,使用SafeObjectConverter处理不一致格式

  7. AOT兼容性:在原生AOT场景下,优先使用源生成和JsonTypeInfo版本的转换器

版本历史

v1.0.0.2 (最新版本)

  • ✨ 新增 SafeObjectConverter<T> 通用对象转换器
  • ✨ 支持空数组 [] 转换为 null 的场景
  • ✨ 新增 CreateSafeOptionsForSourceGeneration() 方法支持源生成
  • 🚀 完全兼容原生AOT编译
  • 📝 完善文档和使用示例

v1.0.0.1

  • 🎉 首次发布
  • ✨ 提供基础数据类型的安全转换器
  • ✨ 支持可空类型转换
  • ✨ 提供多种预配置选项

许可证

本项目采用 Apache 2.0 许可证。详情请参阅 LICENSE 文件。

贡献

欢迎提交问题报告和改进建议。如果您想贡献代码,请提交拉取请求。

作者

  • LiuPengLai - 甲壳虫科技

欢迎提交问题和功能请求。 QQ Group: 1054304346

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.
  • net9.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0.3 216 10/13/2025
1.0.0.2 140 10/4/2025
1.0.0.1 204 10/2/2025
1.0.0 208 9/30/2025

支持NET10