How to pass abstract class to Asp.Net WebApi using Json formatter?
<p>Basically, I'm trying to make my WebApi more generic:</p>

<p>Model:</p>

<pre><code>public abstract class A {}
public class B : A { }
</code></pre>

<p>Client:</p>

<pre><code>using (var client = new HttpClient())
{
    client.BaseAddress = new Uri("http://localhost:49611/");  
    var aList = List&lt;A&gt; { new B() };
    var response = await client.PostAsJsonAsync("api/a", aList);
}
</code></pre>

<p>WebApi controller:</p>

<pre><code>public class AController : ApiController
{
    public void Post([FromBody]List&lt;A&gt; aList)
    {
        // ...
    }
}
</code></pre>

<p>Trying to execute this code, I get an empty list in AController (because A is abstract).</p>

<p>If I remove "abstract" for class A, then I get an item in aList, the type is A, not B as I would expect.</p>

<p>From what I googled, I thought, <code>TypeNameHandling.Auto</code> should be the solution as</p>

<pre><code>public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        //...

        config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto;
    }
}
</code></pre>

<p>However, it doesn't work for me.</p>

<p>However, as a test, I do see <code>TypeNameHandling.Auto</code> working if I use JsonConverter directly:</p>

<pre><code>var aList = List&lt;A&gt; { new B() };
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto };
var str = JsonConvert.SerializeObject(aList, Formatting.Indented, settings);
var obj = JsonConvert.DeserializeObject&lt;List&lt;A&gt;&gt;(str, settings);
</code></pre>

<p>In this case, I do get a list of B (instead of A) in obj.</p>

<p><strong>So, why it doesn't work for my WebApi?</strong></p>

<p>I found this <a href="https://stackoverflow.com/questions/20167895/json-net-typenamehandling-auto-and-asp-web-api-controller-gives-unexpected-behav">post</a>, which is more than two years old, saying "Web API does not use this overload" of <code>public void Serialize(JsonWriter jsonWriter, object value, Type objectType);</code>. I can't believe it's still true after two years. Anyway, in the accepted answer of that post, Kiran provided a custom json formatter, which should fix this problem. However, when I try to plug it into my <code>WebApiConfig</code>, it doesn't work for me. In fact, the overridden <code>WriteToStreamAsync</code> doesn't get called at all - really strange.</p>

<p>Here is Kiran's code:</p>

<pre><code>public class CustomJsonFormatter : JsonMediaTypeFormatter
{
    public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
    {
        try
        {
            Encoding effectiveEncoding = SelectCharacterEncoding(content == null ? null : content.Headers);

            if (!UseDataContractJsonSerializer)
            {
                using (JsonTextWriter jsonTextWriter = new JsonTextWriter(new StreamWriter(writeStream, effectiveEncoding)) { CloseOutput = false })
                {
                    if (Indent)
                    {
                        jsonTextWriter.Formatting = Newtonsoft.Json.Formatting.Indented;
                    }

                    JsonSerializer jsonSerializer = JsonSerializer.Create(this.SerializerSettings);
                    jsonSerializer.Serialize(jsonTextWriter, value, type); //NOTE: passing in 'type' here
                    jsonTextWriter.Flush();
                }
            }
            else
            {
                return base.WriteToStreamAsync(type, value, writeStream, content, transportContext);
            }

            return TaskHelpers.Completed();
        }
        catch (Exception e)
        {
            return TaskHelpers.FromError(e);
        }
    }
}

internal class TaskHelpers
{
    private static readonly Task _defaultCompleted = FromResult&lt;AsyncVoid&gt;(default(AsyncVoid));

    /// &lt;summary&gt;
    /// Used as the T in a "conversion" of a Task into a Task{T}
    /// &lt;/summary&gt;
    private struct AsyncVoid
    {
    }

    internal static Task&lt;TResult&gt; FromResult&lt;TResult&gt;(TResult result)
    {
        TaskCompletionSource&lt;TResult&gt; tcs = new TaskCompletionSource&lt;TResult&gt;();
        tcs.SetResult(result);
        return tcs.Task;
    }

    /// &lt;summary&gt;
    /// Returns an error task. The task is Completed, IsCanceled = False, IsFaulted = True
    /// &lt;/summary&gt;
    internal static Task FromError(Exception exception)
    {
        return FromError&lt;AsyncVoid&gt;(exception);
    }

    /// &lt;summary&gt;
    /// Returns an error task of the given type. The task is Completed, IsCanceled = False, IsFaulted = True
    /// &lt;/summary&gt;
    /// &lt;typeparam name="TResult"&gt;&lt;/typeparam&gt;
    internal static Task&lt;TResult&gt; FromError&lt;TResult&gt;(Exception exception)
    {
        TaskCompletionSource&lt;TResult&gt; tcs = new TaskCompletionSource&lt;TResult&gt;();
        tcs.SetException(exception);
        return tcs.Task;
    }

    /// &lt;summary&gt;
    /// Returns a completed task that has no result. 
    /// &lt;/summary&gt;        
    internal static Task Completed()
    {
        return _defaultCompleted;
    }
}
</code></pre>

<p>Here is my WebApiConfig:</p>

<pre><code>public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        // Configure Web API to use only bearer token authentication.
        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        config.formatters.clear();
        config.Formatters.Add(new CustomJsonFormatter() { SerializerSettings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto } });
    }
}
</code></pre>

<p>Anybody has a clue?</p>

<p><strong>UPDATE and SOLUTION:</strong></p>

<p>Okay, after some struggle, I figured it out myself. The problem is in client request using <code>clien.PostAsJsonAsync</code>. I have to use another function <code>PostAsync</code> with formatter parameter to add <code>TypeNameHandling.Auto</code>, as follows.</p>

<pre><code>var formatter = new JsonMediaTypeFormatter() { SerializerSettings = new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto } };
var response = await client.PostAsync("api/a", aList, formatter);
</code></pre>

<p>With this and <code>TypeNameHandling.Auto</code> in <code>WebApiConfig.cs</code> together, derived classes are correctly deserialized and serialized.</p>