1

I have endpoint which doesn't have [FromBody] parameter:

    [HttpPost("{id:int}/publish")]
    public async Task<IActionResult> Publish()
    {
        <do some stuff>
        return Ok();
    }

But now I need to add [FromBody] parameter in the way that old code is still able to use this endpoint without parameter:

    [HttpPost("{id:int}/publish")]
    public async Task<IActionResult> Publish([FromBody] PublishRequest request)
    {
        <do some stuff>
        return Ok();
    }

But if I add it in this way and try to call this endpoint with empty body, i got 415 (Unsupported Media Type) response back.

I want to make this change backward compatible. So it should be possible to use this endpoint without request body and content-type header. Is is possible?

ant
  • 1,107
  • 2
  • 12
  • 23
  • Just curious: where does the ID parameter go? How are you referring to it in your ? I would have expected it on the method signature. – Richard Jun 02 '20 at 10:29
  • 1
    It seems that optional `FromBody` parameters are not supported ATM, but it seems in [this](https://github.com/dotnet/aspnetcore/issues/6878#issuecomment-595515755) github issue a workaround is posted. – Guru Stron Jun 02 '20 at 10:33
  • @GuruStron, It's exactly what i need! You can post your comment as answer and i will upvote it! – ant Jun 02 '20 at 11:05
  • @ant glad it helped! added as an answer. – Guru Stron Jun 02 '20 at 11:07
  • Your question looks a lot like this one: https://stackoverflow.com/questions/44538772/asp-net-core-form-post-results-in-a-http-415-unsupported-media-type-response Does your solution allow for a [FromForm] in stead of [FromBody]? – Richard Jun 02 '20 at 10:40

2 Answers2

2

It seems that optional FromBody parameters are not supported ATM, but in this github issue was posted a possible workaround:

public class SomeClassModelBinder : IModelBinder
{
    public async Task BindModelAsync(ModelBindingContext bindingContext)
    {
        var stream = bindingContext.HttpContext.Request.Body;
        string body;
        using (var reader = new StreamReader(stream))
        {
            body = await reader.ReadToEndAsync();
        }
        var someClass = JsonConvert.DeserializeObject<SomeClass>(body);

        bindingContext.Result = ModelBindingResult.Success(someClass);
    }
}

[FromBody, ModelBinder(BinderType = typeof(SomeClassModelBinder))] SomeClass request,
Guru Stron
  • 102,774
  • 10
  • 95
  • 132
0

You can make the PublishRequest optional.

[HttpPost("{id:int}/publish")]
public async Task<IActionResult> Publish([FromBody] PublishRequest? request)
{
    // <do some stuff>
    return Ok();
}
Marius Steinbach
  • 548
  • 7
  • 19