Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# HttpClient PostAsync turns 204 into 404

Given this WebApi service:

[ActionName("KillPerson")]
[HttpPost]
public void KillPerson([FromBody] long id)
{
    // Kill
}

And this HttpClient PostAsync call:

var httpClient = new HttpClient { BaseAddress = new Uri(ClientConfiguration.ApiUrl) };
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var serializerSettings = new JsonSerializerSettings
{
    PreserveReferencesHandling = PreserveReferencesHandling.Objects,
    Formatting = Formatting.Indented,
    ReferenceLoopHandling = ReferenceLoopHandling.Serialize
};
var serializedParameter = JsonConvert.SerializeObject(parameter, serializerSettings);
var httpContent = new StringContent(serializedParameter, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(serviceUrl, httpContent).ConfigureAwait(false);
response.EnsureSuccessStatusCode();

I would expect response.EnsureSuccessStatusCode(); to succede but it throws a 404 instead. The funny thing is that fiddler tells med that the webapi service is returning 204 as expected and when I debug it the KillPerson runs without issue.

Update: I Have determined that this only happens when the client code is within a PCL or Silverlight 5 project. The exact same code will give the expected 204 if I duplicate it in a Windows forms application. If i point the Windows Forms app to client code contained in a PCL it gives me the 404 Again.

Update2: This resolves the issue (though it bothers me no end that I should need to do it):

[ActionName("KillPerson")]
[HttpPost]
public HttpResponseMessage KillPerson([FromBody] long id)
{
    return this.Request.CreateResponse(HttpStatusCode.OK);
}

This reintroduces the 404 (fiddler still says 204 and non-silverlight client runs fine)

[ActionName("KillPerson")]
[HttpPost]
public HttpResponseMessage KillPerson([FromBody] long id)
{
    return this.Request.CreateResponse(HttpStatusCode.NoContent);
}

Update 3 (resolved): Finally figured this out. Seems you get a choice of using either browser or client HTTP handling in Silverlight. When using browser HTTP handling a lot of stuff is unsupported - including various response codes and headers. Adding these lines before calling HttpClient fixed it:

WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);
WebRequest.RegisterPrefix("https://", WebRequestCreator.ClientHttp);
like image 394
user2083690 Avatar asked Jan 17 '14 10:01

user2083690


2 Answers

Finally figured this out. Seems you get a choice of using either browser or client HTTP handling in Silverlight. When using browser HTTP handling a lot of stuff is unsupported - including various response codes and headers. Adding these lines before calling HttpClient fixed it:

WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);
WebRequest.RegisterPrefix("https://", WebRequestCreator.ClientHttp);
like image 89
user2083690 Avatar answered Oct 19 '22 20:10

user2083690


Adding the HttpResponseMessage returntype to the method is the documented way of doing this, so the solution you have found is the best really.

But if you don't want to change all your void methods that way, an alternative could be to add a delegating handler to change the response code on the fly - something like this:

public class ResponseHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var response = base.SendAsync(request, cancellationToken);

        if (request.Method == HttpMethod.Post)
        {
            response.Result.StatusCode = response.Result.IsSuccessStatusCode ? System.Net.HttpStatusCode.OK : response.Result.StatusCode;
        }
        return response;
   }
}

Note: This will change the statuscode for all your post methods (when successful). You would have to add some code if you only want it done for specific routes/methods (if you need different post methods to be treated differently).

like image 33
CarllDev Avatar answered Oct 19 '22 20:10

CarllDev