ASP 5 vNext WebAPI Abstract/Inherited Classes

Good evening everyone, I've been fighting vNext, Web API and abstract classes. I just want to be able to pass an array into my API of a bunch of different types that all inherit a base class. Turns out it's a configuration option as vNext uses Newtonsoft.JSON to do the serialize/deserialize it was just a matter of finding it.

Here's an example what I want passed into my API.

public abstract class FilterBase
{
}

public class Filter1 : FilterBase
{
    public string FilterString { get; set; }
}

public class Filter2 : FilterBase
{
    public string DifferentFilterString { get; set; }
}

public class Query
{
    public FilterBase[] Filters
    {
        get; set;
    }
}

Now, I want to pass it into my WebApi controller and have it actually deserialized correctly. The hardest part was getting vNext to deserialize to the correct types, it kept trying to only deserialize the FilterBase. I found that by making FilterBase a regular class and not an abstract. So, to make vNext work....in your Startup.cs file, in ConfigureServices(IServiceCollection) method, you need to configure the MvcJsonOptions (namely the TypeNameHandling).

Now, I want to pass it into my WebApi controller and have it actually deserialized correctly. The hardest part was getting vNext to deserialize to the correct types, it kept trying to only deserialize the FilterBase. I found that by making FilterBase a regular class and not an abstract. So, to make vNext work....in your Startup.cs file, in ConfigureServices(IServiceCollection) method, you need to configure the MvcJsonOptions (namely the TypeNameHandling).

services.Configure<MvcJsonOptions>((options) =>
{
    options.SerializerSettings.MissingMemberHandling = MissingMemberHandling.Ignore;
    options.SerializerSettings.MaxDepth = 32;
    options.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;
});

Now, the json object will get deserialized to the correct type as long as the additional $type property is passed in. In your client you can make sure it does that by doing something like this:

  1. Be sure to add the webapi library to your dependencies in the project.json: Microsoft.AspNet.WebApi.Client
  2. Next, create your client method:
    public async Task<QueryResult> QueryApi(Query query)
    {
        var clientHandler = new HttpClientHandler();
        using (var client = new HttpClient(clientHandler))
        {
            client.BaseAddress = new Uri("http://localhost:55039");
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    
            var jsonFormatter = new JsonMediaTypeFormatter();
            jsonFormatter.SerializerSettings.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto;
            var content = new ObjectContent<Query>(query, jsonFormatter);
            var httpRequestMessage = new HttpRequestMessage
            {
                Content = content,
                Method = HttpMethod.Post,
                RequestUri = new Uri("http://localhost:55039/Account"),
                Version = HttpVersion.Version11
            };
    
            var response = await client.SendAsync(httpRequestMessage);
            if (response.IsSuccessStatusCode)
            {
                return await response.Content.ReadAsAsync<QueryResult>();
            }
        }
    
        return null;
    }
    
  3. Ok, so now you should have the contracts to go between your client and your api. For your controller action, it's pretty straight forward:
    [HttpPost]
    public Task<QueryResult> Post([FromBody]Query query)
    {
        return Task.FromResult(new QueryResult { Results = query.Filters.Select(x => x.GetType().ToString()).ToArray() });
    }
    

I have a git repository with detailed commit's to show how this is done from a base vNext-beta7 web app using only the WebApi application template. That way there is no extra messy ness.
https://github.com/veccsolutions/WebApiExample