I have a controller with one POST method, which will receive an xml string which can be of 2 types. Eg:
[HttpPost("postObj")]
public async Task<IActionResult> postObj([FromBody]firstClass data)
{
if (data != null)...
I would like to be able to bind to multiple types on the same route ([HttpPost("postObj")]) So that I can receive on http://127.0.0.1:5000/api/postObj with firstClass xml in the body, or secondClass xml in the body, and act accordingly.
I tried making another method with the same route but different type like:
[HttpPost("postObj")]
public async Task<IActionResult> postObj([FromBody]secondClass data)
{
if (data != null)...
but I get "Request matched multiple actions resulting in ambiguity", as expected.
I tried reading the body and doing a check then serializing the xml to the respective object, but that drastically reduced the performance.
I am expecting up to 100 requests per second, and binding using FromBody is giving me that, but manually reading the body and serializing gives me only about 15.
How can I achieve that?
Was playing around with same issue, here is what I end up with:
I wish to have following API:
Also I wish to have separate controller actions, like:
So they can be used by Swashbuckle while generating API documentation.
What is even more important I wish to have built in validation working (which wont work in any other suggested solution).
To make this happen we going to create our own action method selector attribute which will try to deserialize incoming request body and if it will be able to do so then action will be chosen, otherwise next action will be checked.
pros: validation is working, no need for third action and/or base model, will work with swashbuckle
cons: for this actions we are reading and deserializing body twice
note: it is important to rewind stream, otherwise anyone else wont be able to read body
and our controller now will look like this:
Full sample code can be found here
As a disclaimer, I consider this a little bit hacky. I'd push for the object that is being sent to you to be changed to one object which can represent either case or to have the two different object types be posted to two different URIs.
With that out of the way, an option to just make it work would be to create a custom IModelBinder by following this tutorial: https://dotnetcoretutorials.com/2016/12/28/custom-model-binders-asp-net-core/
The key here is that the model you're binding will be a base class with your two different classes derived from it.
You can't define two actions with same route. Action Selector doesn't consider their parameter types. So, why don't you merge this actions;