Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to register Known Types for serialization when using ASP.NET MVC Web API

I have a ASP.NET MVC Web API controller that returns public IEnumerable<IMessage> Get()

It throws exception that I need to register types that derive from IMessage in known types collection passed to DataContractSerializer.

How to register "Known Types" for using with DataContractSerializer and DataContractJSONSerializer in MVC Web API project?

KnownType attribute cannot be placed on interface.

like image 273
Alex Burtsev Avatar asked Jan 25 '13 12:01

Alex Burtsev


1 Answers

You need to put the KnownTypeAttribute on your IMessage implementations:

public interface  IMessage
{
    string Content { get; }
}

[KnownType(typeof(Message))]
public class Message : IMessage {
    public string Content{ get; set; }
}

[KnownType(typeof(Message2))]
public class Message2 : IMessage
{
    public string Content { get; set; }
}

So when calling the following action:

 public IEnumerable<IMessage> Get()
 {
     return new IMessage[] { new Message { Content = "value1" }, 
                             new Message2 { Content = "value2" } };
 }

The result will be this:

<ArrayOfanyType xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <anyType xmlns:d2p1="http://schemas.datacontract.org/2004/07/MvcApplication3.Controllers" i:type="d2p1:Message">
        <d2p1:Content>value1</d2p1:Content>
    </anyType>
    <anyType xmlns:d2p1="http://schemas.datacontract.org/2004/07/MvcApplication3.Controllers" i:type="d2p1:Message2">
       <d2p1:Content>value2</d2p1:Content>
    </anyType>
</ArrayOfanyType>

But this will only work one "way". So you cannot post back the same XML.

In order to the following action should work:

public string Post(IEnumerable<IMessage> messages)

You need to register the known types globally, with configuring a DataContractSerializer and setting up in the GlobalConfiguration.Configuration.Formatters

GlobalConfiguration.Configuration
                   .Formatters
                   .XmlFormatter.SetSerializer<IEnumerable<IMessage>>(
                       new DataContractSerializer(typeof(IEnumerable<IMessage>), 
                           new[] { typeof(Message), typeof(Message2) }));

With using the configuration you don't need the KnownTypeAttribute on your implementation types.

like image 50
nemesv Avatar answered Sep 28 '22 00:09

nemesv



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!