J'ai un service Web API 2 existant et j'ai besoin de modifier l'une des méthodes pour prendre un objet personnalisé comme autre paramètre, actuellement la méthode a un paramètre qui est une simple chaîne provenant de l'URL. Après avoir ajouté l'objet personnalisé en tant que paramètre, j'obtiens maintenant une erreur de type de support 415 non pris en charge lors de l'appel du service à partir d'une application Windows .NET. Fait intéressant, je peux appeler cette méthode avec succès en utilisant javascript et la méthode jquery ajax.
La méthode de service Web API 2 ressemble à ceci:
<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
La méthode autorise à la fois POST
et GET
car l'objet Paging
est facultatif. Si j'appelle cette méthode avec une demande GET
cela fonctionne.
Et le code client .NET simple appelant le service ressemble à ceci:
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
Le client .NET s'exécute sur le framework 4.5 et le service est sur le framework 4.5.2. L'erreur est renvoyée sur la ligne resp = req.GetResponse()
. Certaines choses que j'ai déjà essayées:
req.Accept
sur "application/xml" ou "text/xml"Jusqu'à présent, je continue d'obtenir la même réponse d'erreur 415, peu importe ce que j'essaie.
J'ai mentionné que cela fonctionne lorsqu'il est appelé à partir de javascript, voici mon appel ajax qui fonctionne:
$.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");
}
});
Côté service, il n'y a rien d'extraordinaire à faire avec la configuration de l'itinéraire ou quoi que ce soit d'autre, c'est à peu près toute l'API Web prête à l'emploi 2. Je sais que le routage fonctionne, les appels sont correctement acheminés vers la méthode, ils ne vont pas ailleurs de manière inattendue, alors qu'est-ce qui me manque dans le client .NET? Toute aide est très appréciée!
--- MISE À JOUR ---
J'ai essayé de créer un tout nouveau service d'API Web pour exclure tout problème possible avec le service existant, j'ai créé un contrôleur avec une seule méthode qui prend un objet personnalisé comme paramètre. J'ai ensuite essayé d'appeler cela depuis le client .NET et j'ai eu la même erreur. J'ai également essayé d'utiliser WebClient au lieu de HttpWebRequest, mais j'obtiens toujours la même erreur. C'est aussi quelque chose qui fonctionnait auparavant pour moi avec l'API Web (avant l'API Web 2).
--- MISE À JOUR ---
J'ai également essayé de créer une nouvelle application Web à l'aide de l'API Web 1, lorsque j'appelle cela avec un POST mon paramètre d'objet complexe arrive maintenant en null. J'ai un autre service Web exécutant l'API Web 1 et j'ai vérifié que je peux toujours l'appeler avec succès avec des objets complexes. Quel que soit mon problème, il semble que le JSON passe entre le client et le serveur. J'ai vérifié le JSON que j'envoie et sa validité, la définition d'objet est également une correspondance exacte entre le client et le serveur, le JSON doit donc pouvoir être analysé par le serveur.
[~ # ~] résolu [~ # ~]
Après m'être cogné la tête contre le mur pendant quelques jours avec ce problème, il semblait que le problème avait quelque chose à voir avec la négociation du type de contenu entre le client et le serveur. J'ai approfondi cela en utilisant Fiddler pour vérifier les détails de la demande provenant de l'application cliente, voici une capture d'écran de la demande brute capturée par fiddler:
Ce qui manque évidemment, c'est le Content-Type
header, même si je le définissais comme on le voit dans l'exemple de code de mon message d'origine. J'ai trouvé étrange que le Content-Type
jamais vu, même si je le définissais, j'ai donc jeté un coup d'œil à mon autre code (de travail) appelant un service d'API Web différent, la seule différence était que je me trouvais à définir le req.ContentType
propriété avant d'écrire à l'organisme demandeur dans ce cas. J'ai apporté ce changement à ce nouveau code et c'est ainsi que le Content-Type
apparaissait maintenant et j'ai obtenu la réponse attendue du service Web. Le nouveau code de mon client .NET ressemble maintenant à ceci:
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"
C'est tout ce que c'était, la propriété ContentType
devait juste être définie avant d'écrire dans le corps de la requête
Je crois que ce comportement est dû au fait qu'une fois le contenu écrit dans le corps, il est transmis au point de terminaison de service appelé, tout autre attribut relatif à la demande doit être défini avant cela. Veuillez me corriger si je me trompe ou si cela nécessite plus de détails.
J'ai rencontré ce problème lors de l'appel de mon point de terminaison d'API Web et je l'ai résolu.
Dans mon cas, c'était un problème dans la façon dont le client encodait le contenu du corps. Je ne spécifiais pas l'encodage ou le type de support. Leur spécification l'a résolu.
Ne spécifie pas le type de codage, a provoqué une erreur 415:
var content = new StringContent(postData);
httpClient.PostAsync(uri, content);
Spécification de l'encodage et du type de média, succès:
var content = new StringContent(postData, Encoding.UTF8, "application/json");
httpClient.PostAsync(uri, content);
J'ai également rencontré cette erreur.
J'ajoute dans l'en-tête Content-Type
: application/json
. Après le changement, mes soumissions réussissent!
J'essayais d'écrire un code qui fonctionnerait à la fois sur Mac et Windows. Le code fonctionnait bien sous Windows, mais donnait la réponse sous la forme 'Unsupported Media Type' sur Mac. Voici le code que j'ai utilisé et la ligne suivante a également fait fonctionner le code sur Mac:
Request.AddHeader "Content-Type", "application/json"
Voici l'extrait de mon code:
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)