2014-01-17 2 views
11

Учитывая это WebAPI сервис:C# HttpClient PostAsync превращает 204 в 404

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

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

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

Соответствует ли кодировка в службе клиенту? 404 на клиенте предлагают мне, что, когда он раздувал ответ, он не соответствовал ожидаемому. –

+0

Да - это происходит только с методами void (204) - если я изменю службу KillPerson, чтобы вернуть строку, она работает нормально. – user2083690

+0

Учитывая ваше обновление, это не особенно полезно, но я получил правильную функциональность в консольном приложении: (возврат 204) https://gist.github.com/brainwipe/8472430 Заставляет меня думать, что может быть установка AppDomain или кодирование, которое где-то установлено глобально. –

ответ

4

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

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

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

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

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

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

Смежные вопросы