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

如何强制ASP.NET Core默认XML序列化器以基类类型序列化对象

解决ASP.NET Core中XmlSerializer以基类类型序列化派生对象的问题

你的问题核心在于ASP.NET Core默认的XmlSerializerOutputFormatter会根据对象的实际运行时类型(Derived)创建序列化器,而不是你声明的返回类型(Base),这就导致了根节点变成了Derived而非期望的base并带上xsi:type标识。

单独使用XmlSerializer时你指定了typeof(Base)作为序列化类型,所以能得到正确结果,但Web API的格式化器默认没有这么做。我们可以通过自定义格式化器来修复这个问题:

步骤1:自定义XmlSerializerOutputFormatter

创建一个继承自XmlSerializerOutputFormatter的子类,重写CreateSerializer方法,让它使用Action返回的声明类型来创建序列化器:

public class TypedXmlSerializerOutputFormatter : XmlSerializerOutputFormatter
{
    public TypedXmlSerializerOutputFormatter(MvcOptions options) : base(options) { }

    protected override XmlSerializer CreateSerializer(Type type)
    {
        // 如果是ActionContext中存在声明的返回类型,优先使用它
        if (ActionContext != null && ActionContext.ActionDescriptor is ControllerActionDescriptor descriptor)
        {
            var returnType = descriptor.MethodInfo.ReturnType;
            // 处理IActionResult<T>包装的情况
            if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(IActionResult<>))
            {
                returnType = returnType.GetGenericArguments()[0];
            }
            // 处理异步Task<IActionResult<T>>的情况
            else if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
            {
                var taskReturnType = returnType.GetGenericArguments()[0];
                if (taskReturnType.IsGenericType && taskReturnType.GetGenericTypeDefinition() == typeof(IActionResult<>))
                {
                    returnType = taskReturnType.GetGenericArguments()[0];
                }
            }
            return new XmlSerializer(returnType);
        }
        //  fallback到默认逻辑
        return base.CreateSerializer(type);
    }
}

步骤2:替换默认的输出格式化器

在ConfigureServices中,移除默认的XML输出格式化器,替换成我们自定义的版本:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        options.Filters.Add(new ProducesAttribute("application/xml"));
        options.RespectBrowserAcceptHeader = true;
        options.InputFormatters.Add(new XmlSerializerInputFormatter(options));
        
        // 移除默认Xml输出格式化器,添加自定义实现
        var defaultXmlFormatter = options.OutputFormatters.OfType<XmlSerializerOutputFormatter>().FirstOrDefault();
        if (defaultXmlFormatter != null)
        {
            options.OutputFormatters.Remove(defaultXmlFormatter);
        }
        options.OutputFormatters.Add(new TypedXmlSerializerOutputFormatter(options));
        
        options.AllowEmptyInputInBodyModelBinding = true;
    });
}

验证效果

现在你的Index接口返回的XML就会变成你期望的格式:

<base xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xsi:type="Derived" propertyA="some text" propertyB="some other text" />

关键说明

  • 确保你的基类Base上已经添加了[XmlInclude(typeof(Derived))],这是XmlSerializer识别派生类型的必要条件,你已经正确配置了这一点。
  • 自定义格式化器处理了同步和异步Action的返回类型,覆盖了常见的IActionResult和Task<IActionResult>场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 16:42:38