user1824269
user1824269

Reputation: 633

ASP.NET Web API Controller Specific Serializer

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

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?

Upvotes: 13

Views: 3379

Answers (5)

Rob
Rob

Reputation: 4947

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
}

Upvotes: 2

Mark Jones
Mark Jones

Reputation: 12184

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
{

Upvotes: 10

user1824269
user1824269

Reputation: 633

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.

Upvotes: 1

Jason Meckley
Jason Meckley

Reputation: 7591

the controllers actions themselves should not be concerned with how the data is serialized. yo should be able to request the data and any format necessary the operation to retrieve the data would be the same.

by default web api serialized to json objects. however if you set the content type of the request to xml is should return the same result, but formatted as xml instead of json.

Upvotes: 0

Daniel A. White
Daniel A. White

Reputation: 190907

I think you could write a custom ActionFilterAttribute.

In OnActionExecuting, store away the original values in the HttpContext and then in OnActionExecuted, restore the original values.

Upvotes: 0

Related Questions