如何确保Refit调用API时始终携带!DOCTYPE声明?
问题
使用Refit调用API时,必须在XML请求内容中包含<!DOCTYPE>声明,否则会收到400错误:
No message type defined for xml root node 'greeting, line 45:16
Technical ID 14f2a71af84#2fef8552034a12
当前配置代码如下:
Program.cs中的Refit客户端配置:
services .AddRefitClient<IEndpointApi>(new() { ContentSerializer = new XmlContentSerializer() });
模型类定义:
[XmlSchemaProvider("hello.dtd")] [XmlType("greeting")] [XmlRoot("greeting")] public class Greeting { [XmlText] public string Text { get; set; } }
Refit客户端接口:
public interface IEndpointApi { [Post("/endpoint")] Task<Response> SendData([Body] Greeting greeting); }
需要实现每次发送请求时,XML内容包含如下格式的DOCTYPE声明:
<?xml version="1.0"?> <!DOCTYPE greeting SYSTEM "hello.dtd"> <greeting>Hello, world!</greeting>
解决方案
要在Refit的XML请求中添加DOCTYPE声明,需要自定义XmlContentSerializer,重写序列化逻辑以注入DOCTYPE。
步骤1:创建自定义XmlContentSerializer类
public class CustomXmlContentSerializer : XmlContentSerializer { private readonly string _rootElementName; private readonly string _dtdPath; public CustomXmlContentSerializer(string rootElementName, string dtdPath) { _rootElementName = rootElementName; _dtdPath = dtdPath; } protected override XmlWriterSettings CreateXmlWriterSettings() { var settings = base.CreateXmlWriterSettings(); // 确保输出XML版本声明 settings.OmitXmlDeclaration = false; return settings; } public override async Task<HttpContent> SerializeAsync<T>(T item, CancellationToken cancellationToken) { if (item == null) return await base.SerializeAsync(item, cancellationToken); var stringWriter = new StringWriter(); using var xmlWriter = XmlWriter.Create(stringWriter, CreateXmlWriterSettings()); // 写入DOCTYPE声明 xmlWriter.WriteDocType(_rootElementName, null, _dtdPath, null); // 序列化对象到XML var serializer = new XmlSerializer(typeof(T)); serializer.Serialize(xmlWriter, item); var content = new StringContent(stringWriter.ToString(), Encoding.UTF8, "application/xml"); return content; } }
步骤2:替换原有序列化器配置
在Program.cs中,用自定义序列化器替换默认的XmlContentSerializer:
services .AddRefitClient<IEndpointApi>(new() { // 传入对应根元素名和DTD路径 ContentSerializer = new CustomXmlContentSerializer("greeting", "hello.dtd") });
步骤3:验证模型特性(可选)
你的Greeting类已标注[XmlRoot("greeting")]和[XmlSchemaProvider("hello.dtd")],这些特性可保留,与自定义序列化器逻辑兼容,确保XML结构符合要求。
修改完成后,每次发送请求时XML内容会自动包含指定的DOCTYPE声明,满足接口校验要求。
内容的提问来源于stack exchange,提问作者H. Pauwelyn
相关产品推荐
相关产品推荐

