Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET Web API Controller Specific Serializer

I've a self host Web API with 2 controllers:

  • For controller 1, I need default DataContractSerializer (I'm exposing EF 5 POCO)
  • For controller 2, I need XmlFormatter with parameter UseXmlSerializer set to true (I'm exposing an XmlDocument)

I've tried to set formatters during controller initialization, but the configuration seems to be global, affecting all controllers:

public class CustomConfigAttribute : Attribute, IControllerConfiguration
{
    public void Initialize(HttpControllerSettings settings,
    HttpControllerDescriptor descriptor)
    {
        settings.Formatters.XmlFormatter.UseXmlSerializer = true;

    }
}

How can I solve this?

like image 233
user1824269 Avatar asked Nov 14 '12 16:11

user1824269


3 Answers

You were very much on the right track. But you need to initallise a new instance of the XmlMediaTypeFormatter in your config attributes otherwise you will affect the global reference.

As you know, you need to create 2 attributes based on the IControllerConfiguration interface.

public class Controller1ConfigAttribute : Attribute, IControllerConfiguration
{
    public void Initialize(HttpControllerSettings controllerSettings,
                           HttpControllerDescriptor controllerDescriptor)
    {
        var xmlFormater = new XmlMediaTypeFormatter {UseXmlSerializer = true};

        controllerSettings.Formatters.Clear();
        controllerSettings.Formatters.Add(xmlFormater);
    }
}

public class Controller2ConfigAttribute : Attribute, IControllerConfiguration
{
    public void Initialize(HttpControllerSettings controllerSettings,
                           HttpControllerDescriptor controllerDescriptor)
    {
        var xmlFormater = new XmlMediaTypeFormatter();
        controllerSettings.Formatters.Clear();
        controllerSettings.Formatters.Add(xmlFormater);
    }
}

Then decorate your controllers with the relevant attribute

[Controller1ConfigAttribute]
public class Controller1Controller : ApiController
{

[Controller2ConfigAttribute]
public class Controller2Controller : ApiController
{
like image 109
Mark Jones Avatar answered Oct 18 '22 02:10

Mark Jones


Configuration:

config.Formatters.Remove(config.Formatters.JsonFormatter);
config.Formatters.Insert(0, new CustomXmlMediaTypeFormatter());

The Custom formatter:

public class CustomXmlMediaTypeFormatter : XmlMediaTypeFormatter
{
    public CustomXmlMediaTypeFormatter()
    {
        UseXmlSerializer = true;
    }
}

This seems to work, ok not so elegant. Removing default Xml Formatter does not work, so I concluded that the framework is somehow still using it.

like image 36
user1824269 Avatar answered Oct 18 '22 01:10

user1824269


Mark Jones' answer has a big downside: By clearing all formatters it is not possible to request different ContentTypes and make use of the relevant formatter.

A better way to enable the XMLSerializer per Controller is to replace the default formatter.

public class UseXMLSerializerAttribute : Attribute, IControllerConfiguration
{
    public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
    {
        // Find default XMLFormatter
        var xmlFormatter = controllerSettings.Formatters.FirstOrDefault(c => c.SupportedMediaTypes.Any(x => x.MediaType == "application/xml"));

        if (xmlFormatter != null)
        {
            // Remove default formatter
            controllerSettings.Formatters.Remove(xmlFormatter);
        }

        // Add new XMLFormatter which uses XmlSerializer
        controllerSettings.Formatters.Add(new XmlMediaTypeFormatter { UseXmlSerializer = true });
    }
}

And use it like this:

[UseXMLSerializer]
public TestController : ApiController
{
    //Actions
}
like image 20
Rob Avatar answered Oct 18 '22 02:10

Rob