Ошибка неподдерживаемого типа HTTP 415 при вызове конечной точки Web API 2

У меня есть существующая служба Web API 2 и вам нужно изменить один из методов, чтобы использовать пользовательский объект в качестве другого параметра, в настоящее время метод имеет один параметр, который является простой строкой, исходящей из URL-адреса. После добавления пользовательского объекта в качестве параметра я получаю 415 неподдерживаемый тип носителя при вызове службы из приложения .NET windows. Интересно, что я могу успешно вызвать этот метод с помощью javascript и метода jQuery ajax.

Метод службы Web API 2 выглядит следующим образом:

<HttpPost>
<HttpGet>
<Route("{view}")>
Public Function GetResultsWithView(view As String, pPaging As Paging) As HttpResponseMessage
   Dim resp As New HttpResponseMessage
   Dim lstrFetchXml As String = String.Empty
   Dim lstrResults As String = String.Empty

   Try
      '... do some work here to generate xml string for the response
      '// write xml results to response
      resp.Content = New StringContent(lstrResults)
      resp.Content.Headers.ContentType.MediaType = "text/xml"
      resp.Headers.Add("Status-Message", "Query executed successfully")
      resp.StatusCode = HttpStatusCode.OK
   Catch ex As Exception
      resp.StatusCode = HttpStatusCode.InternalServerError
      resp.Headers.Add("Status-Message", String.Format("Error while retrieving results from view {0}: {1}", view, ex.Message))
   End Try
   Return resp
End Function

Метод допускает как POST, так и GET, потому что объект Paging не является обязательным. Если я вызываю этот метод с запросом GET, он работает.

И простой клиентский код .NET, вызывающий службу, выглядит следующим образом:

Dim uri As String = BASE_URI + "fetch/someview"
Dim resp As HttpWebResponse
Dim sr As StreamReader
Dim lstrResponse As String
Dim reqStream As Stream
Dim bytData As Byte()
Dim req As HttpWebRequest = WebRequest.Create(uri)
Dim lstrPagingJSON As String
Dim lPaging As New Paging
Try
   lPaging.Page = 1
   lPaging.Count = 100
   lPaging.PagingCookie = ""
   req.Method = "POST"
   lstrPagingJSON = JsonSerializer(Of Paging)(lPaging)
   bytData = Encoding.UTF8.GetBytes(lstrPagingJSON)
   req.ContentLength = bytData.Length
   reqStream = req.GetRequestStream()
   reqStream.Write(bytData, 0, bytData.Length)
   reqStream.Close()
   req.ContentType = "application/json"

   resp = req.GetResponse()

   sr = New StreamReader(resp.GetResponseStream, Encoding.UTF8)
   lstrResponse = sr.ReadToEnd
   '// do something with the response here
Catch exweb As WebException
   txtOutput.AppendText("Error during request: " + exweb.Message)
Catch ex As Exception
   txtOutput.AppendText(String.Format("General error during request to {0}: {1}", uri, ex.Message))
End Try

Клиент .NET работает на платформе 4.5, а служба - на платформе 4.5.2. Ошибка выводится на строку resp = req.GetResponse(). Некоторые вещи, которые я уже пробовал:

  • на клиенте, установите для параметра req.Accept значение "application/xml" или "Текст/XML"
  • в методе службы, удалите строку `resp.Content.Headers.ContentType.MediaType = "text/xml"
  • заменить содержимое ответа XML на какой-то статический JSON, попытался исключить любые проблемы с отправкой в ​​JSON по запросу и получить XML обратно в ответ

До сих пор я получаю тот же ответ на ошибку 415 независимо от того, что я пытаюсь сделать.

Я упомянул об этом, когда вызывается из javascript, здесь работает мой ajax-вызов:

$.ajax({
   headers: {},
   url: "api/fetch/someview",
   type: "POST",
   data: "{Count:100,Page:1,PagingCookie:\"\"}",
   contentType: "application/json; charset=utf-8",
   dataType: "xml",
   success: function (data) {
      alert("call succeeded");
   },
   failure: function (response) {
      alert("call failed");
   }
});

На стороне обслуживания ничего не происходит с конфигурацией маршрута или чем-то еще, это почти все готовые Web-API 2. Я знаю, что маршрутизация работает, вызовы правильно маршрутизируются в метод, они не собираются куда-то еще неожиданно, так что мне не хватает в .NET-клиенте? Любая помощь очень ценится!

--- UPDATE ---
Я попытался создать совершенно новую службу веб-API, чтобы исключить любые возможные проблемы с существующей службой, я создал контроллер с единственным методом, который принимает в качестве параметра пользовательский объект. Затем я попытался называть это из .NET-клиента и получил ту же ошибку. Я также пытался использовать WebClient вместо HttpWebRequest, но все равно получаю ту же ошибку. Это также то, что ранее работало для меня с веб-API (до веб-API 2).

--- UPDATE ---
Я также попытался создать новое веб-приложение с использованием Web API 1, когда я вызываю это с помощью POST, мой комплексный параметр объекта теперь имеет значение null. У меня есть еще одна веб-служба, работающая с веб-интерфейсом API 1 и проверенная, что я все еще могу успешно ее разрешить с помощью сложных объектов. Независимо от моей проблемы, это похоже на что-то с JSON, проходящим между клиентом и сервером. Я проверил JSON, который я отправляю, и его значение действительно, определение объекта также является точным совпадением между клиентом и сервером, поэтому JSON должен быть проанализирован сервером.

Ответы

Ответ 1

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

Захват Fiddler http-запроса из клиентского приложения

Что явно отсутствует, есть заголовок Content-Type, хотя я устанавливал его как показано в примере кода в моем исходном сообщении. Я подумал, что странно, что Content-Type никогда не появлялся, хотя я его настраивал, поэтому я еще раз посмотрел на другой (рабочий) код, вызывающий другую службу веб-API, единственное различие заключалось в том, что я установил req.ContentType до записи в орган запроса в этом случае. Я сделал это изменение для этого нового кода, и он сделал это, теперь появился Content-Type, и я получил ожидаемый ответ от веб-службы. Новый код моего клиента .NET теперь выглядит следующим образом:

req.Method = "POST"
req.ContentType = "application/json"
lstrPagingJSON = JsonSerializer(Of Paging)(lPaging)
bytData = Encoding.UTF8.GetBytes(lstrPagingJSON)
req.ContentLength = bytData.Length
reqStream = req.GetRequestStream()
reqStream.Write(bytData, 0, bytData.Length)
reqStream.Close()
'// Content-Type was being set here, causing the problem
'req.ContentType = "application/json"

Чтобы все это было, свойство ContentType необходимо было установить перед записью в тело запроса

Я считаю, что это поведение связано с тем, что после того, как контент будет записан в тело, он будет передан в вызываемую конечную точку службы, любые другие атрибуты, относящиеся к запросу, должны быть установлены до этого. Пожалуйста, исправьте меня, если я ошибаюсь, или если это требует более подробной информации.

Ответ 2

Я столкнулся с этой проблемой при вызове моей конечной точки веб-API и решил ее.

В моем случае это была проблема в том, как клиент кодировал содержимое тела. Я не указывал кодировку или тип носителя. Указание их решило это.

Не указав тип кодировки, вызвала ошибку 415:

var content = new StringContent(postData);
httpClient.PostAsync(uri, content);

Указание кодировки и типа носителя, успех:

var content = new StringContent(postData, Encoding.UTF8, "application/json");
httpClient.PostAsync(uri, content);

Ответ 3

Я также испытал эту ошибку.

Я добавляю в заголовок Content-Type: application/json. После внесения изменений мои заявки завершаются успешно!

Ответ 4

Я пытался написать код, который будет работать как на Mac, так и на Windows. Код прекрасно работал в Windows, но на Mac выдавал ответ "Unsupported Media Type". Вот код, который я использовал, и следующая строка заставила код работать и на Mac:

Request.AddHeader "Content-Type", "application/json"

Вот фрагмент моего кода:

Dim Client As New WebClient
Dim Request As New WebRequest
Dim Response As WebResponse
Dim Distance As String

Client.BaseUrl = "http://1.1.1.1:8080/config"
Request.AddHeader "Content-Type", "application/json" *** The line that made the code work on mac

Set Response = Client.Execute(Request)