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

ASP.NET Core如何为XML输出格式化器实现自定义类型依赖注入序列化?

问题描述

在ASP.NET Core项目中,有一个自定义类型MyCustomType,需要依赖外部服务SerializerService进行序列化:

public struct MyCustomType 
{
    private int value;
    public MyCustomType(int value) { this.value = value; }

    public static implicit operator int(MyCustomType value) { return value.value; }
}

public class SerializerService 
{
    public string Encode(MyCustomType val) => ((int)val).ToString();
    public MyCustomType Decode(string val) => new MyCustomType(int.Parse(val));
}

已实现JSON序列化方案,通过自定义转换器MyCustomTypeJsonConverter借助SerializerService完成序列化/反序列化,运行正常:

public class Program 
{
    public static void Main(string[] args) 
    {
        var builder = WebApplication.CreateBuilder(args);
        builder.Services.AddSingleton<SerializerService>();
        builder.Services.AddControllers();
        builder.Services.ConfigureOptions<ConfigureJsonOptions>();
        var app = builder.Build();
        app.MapControllers();
        app.Run();
    }
}

public class MyCustomTypeJsonConverter : JsonConverter<MyCustomType> 
{
    private readonly IServiceProvider sp;

    public MyCustomTypeJsonConverter(IServiceProvider sp) 
    {
        this.sp = sp;
    }

    public override MyCustomType Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)  
    {
        return sp.GetRequiredService<SerializerService>().Decode(reader.GetString());
    }

    public override void Write(Utf8JsonWriter writer, MyCustomType value, JsonSerializerOptions options) 
    {
        writer.WriteStringValue(sp.GetRequiredService<SerializerService>().Encode(value));
    }
}

class ConfigureJsonOptions : IConfigureOptions<JsonOptions> 
{
    private readonly IServiceProvider sp;

    public ConfigureJsonOptions(IServiceProvider sp) 
    {
        this.sp = sp;
    }

    public void Configure(JsonOptions options) 
    {
        options.JsonSerializerOptions.Converters.Add(new MyCustomTypeJsonConverter(sp));
    }
}

现在需要添加XML序列化支持,已将builder.Services.AddControllers();替换为:

builder.Services.AddControllers( options => options.RespectBrowserAcceptHeader = true).AddXmlDataContractSerializerFormatters();

目前考虑通过实现IXmlSerializable接口来定制MyCustomType的XML序列化,但该接口的方法无法直接获取SerializerService:

public struct MyCustomType :  IXmlSerializable 
{
    private int value;
    public MyCustomType(int value) { this.value = value; }
    public static implicit operator int(MyCustomType value) { return value.value; }
    System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() { throw new NotImplementedException(); }
    void IXmlSerializable.ReadXml(System.Xml.XmlReader reader) { /*need to obtain SerializerService here*/}
    void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) { /*need to obtain SerializerService here*/}
}

请问:

  1. 是否存在无需实现IXmlSerializable即可实现自定义类型XML序列化的方案?
  2. 是否有其他适合作为ASP.NET Core输出格式化器、支持自定义类型序列化的XML序列化器?

解决方案

方案一:自定义XML格式化器(无需修改原类型)

直接替换默认的XML格式化器,在自定义格式化器中注入SerializerService处理MyCustomType的序列化逻辑,完全不用改动原结构体:

1. 实现自定义输出格式化器

public class CustomXmlOutputFormatter : XmlSerializerOutputFormatter
{
    private readonly SerializerService _serializerService;

    public CustomXmlOutputFormatter(SerializerService serializerService, XmlWriterSettings writerSettings)
        : base(writerSettings)
    {
        _serializerService = serializerService;
    }

    protected override void Serialize(XmlSerializer xmlSerializer, XmlWriter xmlWriter, object value)
    {
        // 单独处理MyCustomType类型
        if (value is MyCustomType customVal)
        {
            xmlWriter.WriteString(_serializerService.Encode(customVal));
            return;
        }
        // 其他类型沿用默认序列化逻辑
        base.Serialize(xmlSerializer, xmlWriter, value);
    }
}

2. 实现自定义输入格式化器

public class CustomXmlInputFormatter : XmlSerializerInputFormatter
{
    private readonly SerializerService _serializerService;

    public CustomXmlInputFormatter(ILogger<XmlSerializerInputFormatter> logger, SerializerService serializerService, XmlReaderSettings readerSettings, MvcOptions options)
        : base(logger, options, readerSettings)
    {
        _serializerService = serializerService;
    }

    protected override object Deserialize(XmlSerializer xmlSerializer, XmlReader xmlReader)
    {
        // 针对MyCustomType类型做反序列化转换
        if (typeof(MyCustomType) == xmlSerializer.XmlType.Type)
        {
            var strValue = xmlReader.ReadElementContentAsString();
            return _serializerService.Decode(strValue);
        }
        return base.Deserialize(xmlSerializer, xmlReader);
    }
}

3. 注册自定义格式化器

在Program.cs中替换默认XML格式化器:

builder.Services.AddControllers(options => 
{
    options.RespectBrowserAcceptHeader = true;
    
    // 移除默认XML格式化器
    var defaultOutputFormatter = options.OutputFormatters.OfType<XmlSerializerOutputFormatter>().FirstOrDefault();
    if (defaultOutputFormatter != null) options.OutputFormatters.Remove(defaultOutputFormatter);
    
    var defaultInputFormatter = options.InputFormatters.OfType<XmlSerializerInputFormatter>().FirstOrDefault();
    if (defaultInputFormatter != null) options.InputFormatters.Remove(defaultInputFormatter);
    
    // 添加自定义XML格式化器
    var serviceProvider = builder.Services.BuildServiceProvider();
    options.OutputFormatters.Add(new CustomXmlOutputFormatter(
        serviceProvider.GetRequiredService<SerializerService>(),
        new XmlWriterSettings { OmitXmlDeclaration = true }));
    
    options.InputFormatters.Add(new CustomXmlInputFormatter(
        serviceProvider.GetRequiredService<ILogger<XmlSerializerInputFormatter>>(),
        serviceProvider.GetRequiredService<SerializerService>(),
        new XmlReaderSettings(),
        options));
});

方案二:使用序列化代理类

为MyCustomType创建专用的XML序列化代理类,在控制器层完成类型转换,无需修改原结构体:

[XmlRoot("MyCustomType")]
public class MyCustomTypeXmlProxy
{
    [XmlText]
    public string Value { get; set; }

    // 从代理类转换为原类型
    public static explicit operator MyCustomType(MyCustomTypeXmlProxy proxy)
    {
        // 实际项目中建议通过依赖注入获取SerializerService
        var serializer = proxy.GetService<SerializerService>(); 
        return serializer.Decode(proxy.Value);
    }

    // 从原类型转换为代理类
    public static explicit operator MyCustomTypeXmlProxy(MyCustomType customType)
    {
        var serializer = customType.GetService<SerializerService>();
        return new MyCustomTypeXmlProxy { Value = serializer.Encode(customType) };
    }
}

在控制器中使用:

[HttpGet]
public IActionResult Get([FromServices] SerializerService serializer)
{
    MyCustomType customVal = new MyCustomType(123);
    var proxy = new MyCustomTypeXmlProxy { Value = serializer.Encode(customVal) };
    return Ok(proxy);
}

[HttpPost]
public IActionResult Post([FromBody] MyCustomTypeXmlProxy proxy, [FromServices] SerializerService serializer)
{
    MyCustomType customVal = serializer.Decode(proxy.Value);
    // 业务逻辑处理
    return Ok();
}

可选XML序列化器

除了ASP.NET Core默认的DataContractSerializer和XmlSerializer,还可以选择以下第三方序列化库,它们支持自定义规则且能集成到ASP.NET Core格式化器体系:

  • ServiceStack.Text:轻量级序列化库,支持XML/JSON等多种格式,可通过配置自定义类型序列化逻辑
  • Utf8Xml:高性能XML序列化库,提供灵活的自定义类型扩展接口
  • Newtonsoft.Xml:基于Newtonsoft.Json的XML序列化实现,支持类似JSON转换器的自定义扩展

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 18:35:11