Подтвердить что ты не робот

С# HttpClient PostAsync превращает 204 в 404

Учитывая этот сервис WebApi:

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

И этот вызов HttpClient PostAsync:

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();

Я ожидал бы response.EnsureSuccessStatusCode(); чтобы преуспеть, но вместо этого он выбрасывает 404. Самое забавное, что скрипач сообщает, что служба webapi возвращает 204, как ожидалось, и когда я отлаживаю ее, KillPerson запускается без проблем.

Обновление: Я решил, что это происходит только тогда, когда клиентский код находится в рамках проекта PCL или Silverlight 5. Тот же самый код даст ожидаемый 204, если я дублирую его в приложении форм Windows. Если я укажу приложение Windows Forms на клиентский код, содержащийся в PCL, он снова даст мне 404.

Update2: Это решает проблему (хотя мне нечего беспокоиться, что мне нужно это сделать):

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

Это повторяет 404 (скрипач по-прежнему говорит, что 204 и клиент не-Silverlight отлично работают)

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

Обновление 3 (разрешено): Наконец понял это. Кажется, у вас есть выбор использования браузера или клиентской обработки HTTP в Silverlight. При использовании обработки HTTP-браузера множество неподдерживаемых файлов - включая различные коды ответов и заголовки. Добавление этих строк перед вызовом HttpClient исправило это:

WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);
WebRequest.RegisterPrefix("https://", WebRequestCreator.ClientHttp);
4b9b3361

Ответ 1

Наконец понял это. Кажется, у вас есть выбор использования браузера или клиентской обработки HTTP в Silverlight. При использовании обработки HTTP-браузера множество неподдерживаемых файлов - включая различные коды ответов и заголовки. Добавление этих строк перед вызовом HttpClient исправило это:

WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);
WebRequest.RegisterPrefix("https://", WebRequestCreator.ClientHttp);

Ответ 2

Добавление возвращаемого метода HttpResponseMessage к методу является документированным способом этого, поэтому решение, которое вы нашли, действительно лучшее.

Но если вы не хотите изменять все ваши методы void таким образом, альтернативой может быть добавление обработчика делегирования для изменения кода ответа на лету - примерно так:

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;
   }
}

Примечание.. Это изменит код состояния для всех ваших методов публикации (при успешном завершении). Вам нужно будет добавить код, если вы хотите, чтобы это было сделано только для определенных маршрутов/методов (если вам нужно, чтобы разные почтовые методы обрабатывались по-разному).