You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为ASP.NET配置系统创建自定义类型序列化器?

问题

希望创建自定义TimeSpan类型CustomTimeSpan,使其在ASP.NET配置(如appsettings.json)中保持与原生TimeSpan一致的序列化行为。原生配置写法示例:

"TimeSpanProperty":"01:30:45"

需要自定义类型支持同样的写法:

"CustomTimeSpanProperty":"02:30:45"

CustomTimeSpan初始实现:

public readonly struct CustomTimeSpan
{
    private readonly TimeSpan _timeSpan;
    public readonly TimeSpan Value => _timeSpan;

    public CustomTimeSpan(TimeSpan timeSpan)
    {
        _timeSpan = timeSpan;
    }

    // Implicit operator to convert to total milliseconds
    public static implicit operator long(CustomTimeSpan customTimeSpan)
    {
        return (long)customTimeSpan.Value.TotalMilliseconds;
    }
}

已实现基于JsonConverter的自定义转换器,但通过AddJsonOptions注册仅适用于控制器,无法让配置提供者使用该转换器,需了解如何自定义配置序列化逻辑。

解决方案

ASP.NET配置系统(如读取appsettings.json)依赖类型转换机制而非普通JSON序列化,因此不能直接复用JsonConverter。以下两种方案可实现需求:

方法一:实现全局TypeConverter

为CustomTimeSpan编写类型转换器,让配置系统自动识别并完成字符串与自定义类型的转换:

  1. 编写TypeConverter子类:
using System.ComponentModel;
using System.Globalization;

public class CustomTimeSpanConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
    {
        return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
    }

    public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
    {
        if (value is string strValue)
        {
            if (TimeSpan.TryParse(strValue, out var timeSpan))
            {
                return new CustomTimeSpan(timeSpan);
            }
            throw new ArgumentException($"无法将字符串\"{strValue}\"转换为CustomTimeSpan类型");
        }
        return base.ConvertFrom(context, culture, value);
    }

    public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType)
    {
        return destinationType == typeof(string) || base.CanConvertTo(context, destinationType);
    }

    public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
    {
        if (destinationType == typeof(string) && value is CustomTimeSpan customTimeSpan)
        {
            return customTimeSpan.Value.ToString(@"hh:mm:ss.fff");
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }
}
  1. 为CustomTimeSpan添加特性标记:
[TypeConverter(typeof(CustomTimeSpanConverter))]
public readonly struct CustomTimeSpan
{
    // 原有实现保持不变
    private readonly TimeSpan _timeSpan;
    public readonly TimeSpan Value => _timeSpan;

    public CustomTimeSpan(TimeSpan timeSpan)
    {
        _timeSpan = timeSpan;
    }

    public static implicit operator long(CustomTimeSpan customTimeSpan)
    {
        return (long)customTimeSpan.Value.TotalMilliseconds;
    }
}

完成后,配置系统在绑定CustomTimeSpan类型属性时会自动使用该转换器,无需额外注册操作。

方法二:配置绑定阶段指定自定义转换器(.NET 6+)

如果不需要全局生效,可在配置绑定过程中单独指定转换器:

  1. 实现IConfigurationConverter<CustomTimeSpan>接口:
using Microsoft.Extensions.Configuration;

public class CustomTimeSpanConfigConverter : IConfigurationConverter<CustomTimeSpan>
{
    public CustomTimeSpan Convert(object? input)
    {
        if (input is string strValue)
        {
            if (TimeSpan.TryParse(strValue, out var timeSpan))
            {
                return new CustomTimeSpan(timeSpan);
            }
            throw new InvalidOperationException($"无效的CustomTimeSpan格式:{strValue}");
        }
        throw new InvalidOperationException($"无法将类型{input?.GetType().Name}转换为CustomTimeSpan");
    }
}
  1. 绑定配置时注册转换器:
var config = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json")
    .Build();

var options = new YourOptions();
config.Bind(options, binderOptions =>
{
    binderOptions.ConvertUsing(new CustomTimeSpanConfigConverter());
});

该方案灵活性更高,适合仅在特定配置绑定场景中使用自定义转换逻辑的需求。

内容的提问来源于stack exchange,提问作者mshwf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 03:34:53