I have an existing Web API 2 service and need to modify one of the methods to take a custom object as another parameter, currently the method has one parameter which is a simple string coming from the URL. After adding the custom object as a parameter I am now getting a 415 unsupported media type error when calling the service from a .NET windows app. Interestingly, I can successfully call this method using javascript and the jquery ajax method.

The Web API 2 service method looks like this:

<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

该方法同时允许POSTGET,因为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

The .NET client is running on the 4.5 framework and the service is on 4.5.2 framework. The error is thrown at the resp = req.GetResponse() line. Some things I tried already:

  • 在客户端上,将req.Accept值设置为"application/xml"或 "text/xml"
  • in the service method, removed the line `resp.Content.Headers.ContentType.MediaType = "text/xml"
  • replace the XML response content with some static JSON, tried to rule out any problems with sending in JSON on the request and getting XML back on the response

So far I keep getting the same 415 error response no matter what I try.

当从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");
   }
});

在服务端,route config或其他任何东西都没有什么特别之处,它几乎都是现成的Web API 2.我知道路由正在工作,调用被正确地路由到方法,它们不会意外地转到其他地方,所以我在这个过程中遗漏了什么.网络客户端?非常感谢您的帮助!

--- UPDATE ---
I tried to create a completely new Web API service to rule out any possible issues with the existing service, I created a controller with a single method that takes a custom object as the parameter. I then tried calling that from the .NET client and got the same error. I also tried using WebClient instead of HttpWebRequest, but still get the same error. This is also something that previously worked for me with Web API (prior to Web API 2).

--- UPDATE ---
I also tried creating a new web app using Web API 1, when I call that with a POST my complex object parameter is now coming in null. I have another web service running Web API 1 and verified that I can still call that successfully with complex objects. Whatever my problem is, it appears to be something with the JSON passing between the client and server. I have checked the JSON I'm sending it and its valid, the object definition is also an exact match between the client and server so the JSON should be able to be parsed by the server.

推荐答案

SOLVED
After banging my head on the wall for a couple days with this issue, it was looking like the problem had something to do with the content type negotiation between the client and server. I dug deeper into that using Fiddler to check the request details coming from the client app, here's a screenshot of the raw request as captured by fiddler:

Fiddler capture of http request from client app

这里明显缺少的是Content-Type头,尽管我在我的原始帖子的代码示例中设置了它.我觉得奇怪的是,尽管我正在设置Content-Type,但它始终没有通过,所以我再次查看了调用不同Web API服务的其他(正在运行的)代码,唯一的区别是,在这种情况下,在写入请求主体之前,我碰巧设置了req.ContentType属性.我对这段新代码做了修改,这就做到了,Content-Type现在出现了,我从web服务获得了预期的成功响应.我的新代码.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"

That's all it was, the ContentType property just needed to be set prior to writing to the request body

I believe this behavior is because once content is written to the body it is streamed to the service endpoint being called, any other attributes pertaining to the request need to be set prior to that. Please correct me if I'm wrong or if this needs more detail.

Json相关问答推荐

从JSON格式提取数据时分隔通用名称

Jolt-Json转换:通过引用标识符(而不是索引)设置值

使用动态语言jQuery:根据匹配模式提取与其他值匹配的值

将带有::text[]的JSON数组转换未按预期工作

JOLT JSON 将值从一对多转换为一对一

使用 jq 和 awk 拆分大型 JSON 文件

判断golang中解析的json响应中是否存在所需的json键(不是值)

jq:来自嵌套 JSON 的映射

提交后使用 Rails 7 结合 JSON 标签进行标记

使用 SwiftUI 在 API 调用中解码嵌套 JSON 响应时遇到问题

如何在 Django 的模板语言中获取 json 键和值?

如何让 JSON.NET 忽略对象关系?

Swift - 将图像从 URL 写入本地文件

Jackson 的@JsonView、@JsonFilter 和 Spring

Python - 如何将 JSON 文件转换为数据框

如何将 LinkedTreeMap 转换为 gson JsonObject

waitUntilAllTask​​sAreFinished 错误 Swift

带有 Jackson 的不可变 Lombok 注释类

如何对 jq 中的 map 数组中的值求和?

在 .NET 中缩小缩进的 JSON 字符串