Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

POST to Web API action with IEnumerable<Interface> type parameter

I am trying to post to a Web API method from a client, as follows:

// Create list of messages that will be sent
IEnumerable<IMessageApiEntity> messages = new List<IMessageApiEntity>();
// Add messages to the list here. 
// They are all different types that implement the IMessageApiEntity interface.

// Create http client
HttpClient client = new HttpClient {BaseAddress = new Uri(ConfigurationManager.AppSettings["WebApiUrl"])};
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

// Post to web api
HttpResponseMessage response = client.PostAsJsonAsync("Communications/Messages", messages).Result;

// Read results
IEnumerable<ApiResponse<IMessageApiEntity>> results = response.Content.ReadAsAsync<IEnumerable<ApiResponse<IMessageApiEntity>>>().Result;

My Web API controller action looks like this:

public HttpResponseMessage Post([FromBody]IEnumerable<IMessageApiEntity> messages)
{
    // Do stuff
}

The problem I am having is that messages is always empty (but not null) when coming into the web API controller action. I have verified in the debugger that the messages object on the client side does have items in it right before being posted.

I suspect it might have something to do with the interface type not being converted to a concrete type when trying to pass the objects, but I don't know how to go about making it work. How can I achieve this?

like image 617
mayabelle Avatar asked Nov 20 '13 18:11

mayabelle


People also ask

What is IEnumerable interface in C#?

IEnumerable is an interface defining a single method GetEnumerator() that returns an IEnumerator interface. It is the base interface for all non-generic collections that can be enumerated. This works for read-only access to a collection that implements that IEnumerable can be used with a foreach statement.

What is the difference between IActionResult and IHttpActionResult?

What is the difference between IHttpActionResult and IActionresult ? "IActionResult is the new abstraction that should be used in your actions. Since Web API and MVC frameworks have been unified in ASP.NET Core, various IActionResult implementations can handle both traditional API scenarios.".


1 Answers

I figured out how to do it without a custom model binder. Posting the answer in case anyone else has this issue...

Client:

// Create list of messages that will be sent
IEnumerable<IMessageApiEntity> messages = new List<IMessageApiEntity>();
// Add messages to the list here. 
// They are all different types that implement the IMessageApiEntity interface.

// Create http client
HttpClient client = new HttpClient {BaseAddress = new Uri(ConfigurationManager.AppSettings["WebApiUrl"])};
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

// Post to web api (this is the part that changed)
JsonMediaTypeFormatter json = new JsonMediaTypeFormatter
{
    SerializerSettings =
    {
        TypeNameHandling = TypeNameHandling.All
    }
};
HttpResponseMessage response = client.PostAsync("Communications/Messages", messages, json).Result;

// Read results
IEnumerable<ApiResponse<IMessageApiEntity>> results = response.Content.ReadAsAsync<IEnumerable<ApiResponse<IMessageApiEntity>>>().Result;

Add to Register method in WebApiConfig.cs:

config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;

The key is to send the type as part of the json and turn on automatic type name handling, so that web API can figure out what type it is.

like image 194
mayabelle Avatar answered Sep 20 '22 14:09

mayabelle