How could I be sure that every time Refit sends an API call to an endpoint the !DOCTYPE
declaration is defined.
<?xml version="1.0"?>
<!DOCTYPE greeting SYSTEM "hello.dtd">
<greeting>Hello, world!</greeting>
I've found that when it's missing I got a 400 error response with this content:
No message type defined for xml root node 'greeting, line 45:16
Technical ID 14f2a71af84#2fef8552034a12
Inside the Program
file I've defined this code:
services
.AddRefitClient<IEndpointApi>(new()
{
ContentSerializer = new XmlContentSerializer()
});
The models look like these:
[XmlSchemaProvider("hello.dtd")]
[XmlType("greeting")]
[XmlRoot("greeting")]
public class Greeting
{
[XmlText]
public string Text { get; set; }
}
And the Refit client looks like this:
public interface IEndpointApi
{
[Post("/endpoint")]
Task<Response> SendData([Body] Greeting greeting);
}
Found a solution IHttpContentSerializer
, maybe not the best one but it's working.
public class XmlDocTypeContentSerializer : IHttpContentSerializer
{
/// <summary>Original XmlContentSerializer from Refit but without a possibility to add a !DOCTYPE.</summary>
private readonly XmlContentSerializer _xmlContentSerializer;
public XmlContentSerializerSettings ContentSerializerSettings { get; init; }
public XmlDocTypeContentSerializer() : this(new())
{ }
public XmlDocTypeContentSerializer(XmlContentSerializerSettings settings)
{
// No settings to process DTD or !DOCTYPE on writing... :-(
settings.XmlReaderWriterSettings.ReaderSettings.DtdProcessing = DtdProcessing.Parse;
ContentSerializerSettings = settings;
_xmlContentSerializer = new(settings);
}
public async Task<T?> FromHttpContentAsync<T>(HttpContent content, CancellationToken cancellationToken = default) =>
await _xmlContentSerializer.FromHttpContentAsync<T>(content, cancellationToken);
public string? GetFieldNameForProperty(PropertyInfo propertyInfo) =>
_xmlContentSerializer.GetFieldNameForProperty(propertyInfo);
public HttpContent ToHttpContent<T>(T item)
{
ArgumentNullException.ThrowIfNull(item);
Type type = item.GetType();
StringWriter stringWriter = new();
XmlSerializer xmlSerializer = new(type);
XmlWriter xmlWriter = XmlWriter.Create(stringWriter, ContentSerializerSettings.XmlReaderWriterSettings.WriterSettings);
xmlWriter.WriteDocType(name: "greeting", pubid: null, sysid: "hello.dtd", subset: null);
xmlSerializer.Serialize(xmlWriter, item);
return new StringContent(stringWriter.ToString(), new MediaTypeHeaderValue("application/xml"));
}
}