DEV Community

loading...

AspNet Core and Xml

Mark Davies
Passionate coder
・2 min read

I have been recently working on a legacy api that accepts xml that uses namespaces, and I found the documentation in this space very sparse. So I'm hoping that if I ever have this problem again I can just search for this blog post and read what I wrote πŸ˜‚

So let's talk about xml:

Accepting xml in asp .net core

First of all there is a small piece of code that we need to add to our startup to accept xml in our api:

public void ConfigureServices(IServiceCollection services)
{
    //
    services.AddControllers()
        .AddXmlSerializerFormatters();
    ///
}
Enter fullscreen mode Exit fullscreen mode

This adds the default input and output formatters - which trust me we'll come back to!

If we haev OpenApi connected to our application then we need to tell it that we accept xml:

[ApiController]
public class WeatherController : BaseController
{
    [Produces("application/xml"), Consumes("application/xml")]
    public IActionResult Test()
    {

    }
}
Enter fullscreen mode Exit fullscreen mode

Don't forget to add the correct tag to tell asp where your going to get your information from:

[Produces("application/xml"), Consumes("application/xml")]
public IActionResult Test([FromBody] RequsetModel request)
{

}
Enter fullscreen mode Exit fullscreen mode

Namespaces

When I was looking into this problem this was probably the biggest headache, searching for how to actually add a namespace onto a xml is a nightmare, lots of false information laying around so...... Firstly we want to "declare" which namespaces we want to use, this can go in any class, I opted to create a namespace class:

public static class XmlNamespaces
{
    [XmlNamespaceDeclarations]
    public static XmlSerializerNamespaces Namespaces 
    {
        get
        {
            return new XmlSerializerNamespaces(new[]
            {
                new XmlQualifiedName("", "http://schemas.xmlsoap.org/soap/envelope/"),
                new XmlQualifiedName("xsi", "http://www.w3.org/2001/XMLSchema-instance")
            });
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Please ignore the fact that I'm adding soap envelope namespace, that's just an example πŸ’€ I swear.

Now that we have the namespaces declared we can now add them to our model:



[XmlRoot("Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class RequsetModel 
{
    [XmlElement(Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
    public Header? Header { get; set; }

    [XmlElement(Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
    public BulkActionBody Body { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

now if we were to request the api we should be able to send a request that looks like:

<Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <xsi:Header></xsi:Header/>
    <xsi:Body></xsi:Body/>
</Envelope>
Enter fullscreen mode Exit fullscreen mode

Outputting xml

You know how I said before that we would come back to the default serializers in aspnet core? Well here we go! Turns out declaring these namespaces only works for requests, if we were to return a model that had these attributes on it (with namespaces that were declared) it won't actually add those namespaces.

First we need to override our serializer:


public class XmlOutputSerializer : XmlSerializerOutputFormatter
{
    protected override void Serialize(XmlSerializer xmlSerializer, XmlWriter xmlWriter, object value)
    {
        xmlSerializer.Serialize(xmlWriter, value, XmlNamespaces.Namespaces);
    }
}
Enter fullscreen mode Exit fullscreen mode

This tells the serializer that we want to use the namespaces that we have declared when deserializing xml.

Next we need to tell Asp net core that we want to use this serilizer and not the default one, back to our startup:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options => options.OutputFormatters.Add(new XmlOutputSerializer()))
        .AddXmlSerializerFormatters();
}

Enter fullscreen mode Exit fullscreen mode

And kapow πŸŽ‰πŸŽŠπŸŽŠπŸŽ‰ There's three weeks worth of googling in a 2 minute blog post

Discussion (0)