Search code examples
c#asp.netasp.net-web-apiamazon-ecshttp-patch

JSON Patch HTTP request from client to API (published on AWS) returns "StatusCode: 405, ReasonPhrase: 'Method Not Allowed'"


I have an ASP.NET Core Web API published to Amazon ECS using AWS Fargate with working PATCH request that I have successfully tested using POSTMAN. Now I am trying to make that request in the client side application by following this.

What I have on client side is this:

public async Task<ActionResult> Patch(int companyId, string description)
{
    JsonPatchDocument<CompanyInfo> patchDoc = new JsonPatchDocument<CompanyInfo>();
    patchDoc.Replace(e => e.Description, description);

    var jsonSerializeObject = JsonConvert.SerializeObject(patchDoc);
    Debug.WriteLine(jsonSerializeObject);

    var method = new HttpMethod("PATCH");
    var request = new HttpRequestMessage(method, "api/CompanyInfo/" + companyId)
    {
        Content = new StringContent(jsonSerializeObject, Encoding.Unicode, "application/json")
    };


    response = await _httpClient.SendAsync(request);
    Debug.WriteLine(response);

    return RedirectToAction(nameof(Index));
}

This is what I get in my response:

StatusCode: 405, ReasonPhrase: 'Method Not Allowed', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:
{
  Date: Sat, 26 Nov 2022 06:06:08 GMT
  Connection: keep-alive
  Server: Kestrel
  Content-Length: 0
  Allow: GET, PUT
}

As previously mentioned I have already confirmed the following json patch document using POSTMAN:

[
    {
        "value":"some text value",
        "path":"/Description",
        "op":"replace"
    }
]

The API:


[HttpPatch]
public async Task<ActionResult> PartiallyUpdateCompanyInfo(int companyId, JsonPatchDocument<CompanyInfoForPatchDto> patchDocument)
{
    var companyEntity = await _moviePlanetRepository.GetCompanyById(companyId, false);
    if (companyEntity == null)
    {
        return NotFound();
    }

    var companyToPatch = _mapper.Map<CompanyInfoForPatchDto>(companyEntity);

    patchDocument.ApplyTo(companyToPatch, ModelState);

    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    if (!TryValidateModel(companyToPatch))
    {
        return BadRequest(ModelState);
    }

    _mapper.Map(companyToPatch, companyEntity);
    await _moviePlanetRepository.Save();

    return NoContent();
}

Solution

  • Had to specify that the companyId was a required for the Route. From this

    It wasn't sufficient to provide the above attributes to the methods. It was required to provide the methods' address (and query string, resp.) parameters for these attributes ([HttpPut("{id}")], [HttpDelete("{id}")]), too. (This is particular to ASP.NET Core.)

    [Route("{companyId:int}")]
    [HttpPatch]
    public async Task<ActionResult> PartiallyUpdateCompanyInfo(int companyId, [FromBody]JsonPatchDocument<CompanyInfoForPatchDto> patchDocument)
    {
        var companyEntity = await _moviePlanetRepository.GetCompanyById(companyId, false);
        if (companyEntity == null)
        {
            return NotFound();
        }
    
        var companyToPatch = _mapper.Map<CompanyInfoForPatchDto>(companyEntity);
    
        patchDocument.ApplyTo(companyToPatch, ModelState);
    
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }
    
        if (!TryValidateModel(companyToPatch))
        {
            return BadRequest(ModelState);
        }
    
        _mapper.Map(companyToPatch, companyEntity);
        await _moviePlanetRepository.Save();
    
        return NoContent();
    }