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*/} }
请问:
- 是否存在无需实现
IXmlSerializable即可实现自定义类型XML序列化的方案? - 是否有其他适合作为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
相关产品推荐
相关产品推荐

