16

Ho un servizio Web API 2 esistente e devo modificare uno dei metodi per prendere un oggetto personalizzato come un altro parametro, attualmente il metodo ha un parametro che è un semplice stringa proveniente dall'URL. Dopo aver aggiunto l'oggetto personalizzato come parametro, ora ricevo un errore di tipo di supporto 415 non supportato quando si chiama il servizio da un'app di Windows .NET. È interessante notare che posso chiamare con successo questo metodo utilizzando javascript e il metodo jquery ajax.Errore di tipo di supporto HTTP non supportato 415 quando si chiama endpoint Web API 2

Il metodo di servizio Web API 2 si presenta così:

<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 

Il metodo permette sia POST e GET perché l'oggetto Paging è opzionale. Se chiamo questo metodo con una richiesta GET, funziona.

E il semplice codice client .NET chiamando il servizio assomiglia a questo:

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 

client .NET è in esecuzione sul Framework 4.5 e il servizio è in 4.5.2 quadro. L'errore viene generato sulla riga resp = req.GetResponse(). Alcune cose che ho provato già:

  • sul client, impostare il valore req.Accept a "application/xml" o "text/xml"
  • nel metodo di servizio, rimosso la linea `resp.Content. Headers.ContentType.MediaType = "text/xml"
  • sostituire il contenuto della risposta XML con un po 'statica JSON, ha cercato di escludere eventuali problemi con l'invio in JSON in merito alla richiesta e ottenere XML indietro sulla risposta

Finora continuo a ricevere il stessa risposta all'errore 415, non importa quello che cerco.

ho detto questo funziona quando viene chiamato da JavaScript, ecco la mia ajax chiamata che sta lavorando:

$.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"); 
    } 
}); 

Sul lato di servizio, non c'è niente di speciale in corso con la configurazione percorso o qualsiasi altra cosa, è praticamente tutte le API web out-of-the-box 2. So che il routing funziona, le chiamate vengono indirizzate correttamente al metodo, non vanno in altro modo inaspettatamente, quindi cosa mi manca nel client .NET? Ogni aiuto è molto apprezzato!

--- UPDATE ---
Ho cercato di creare un nuovo servizio Web API per escludere eventuali problemi possibili con il servizio esistente, ho creato un controller con un unico metodo che prende un oggetto personalizzato come il parametro. Ho quindi provato a chiamarlo dal client .NET e ho ottenuto lo stesso errore. Ho anche provato a utilizzare WebClient anziché HttpWebRequest, ma ho ancora lo stesso errore. Questo è anche qualcosa che in precedenza ha funzionato per me con Web API (prima di Web API 2).

--- UPDATE ---
Ho provato anche la creazione di una nuova applicazione web utilizzando Web API 1, quando chiamo che con un post il mio parametro oggetto complesso è ora in arrivo in nulla. Ho un altro servizio web che esegue Web API 1 e ho verificato che posso ancora chiamarlo con successo con oggetti complessi. Qualunque sia il mio problema, sembra essere qualcosa con il JSON che passa tra il client e il server.Ho controllato il JSON che sto inviando e la sua validità, la definizione dell'oggetto è anche una corrispondenza esatta tra il client e il server, quindi il JSON dovrebbe essere analizzato dal server.

+0

ho ottenuto questo errore 415 quando si fa un DELETE e l'aggiunta di un carico utile JSON dove nessuno era necessario. – kmarsh

risposta

35

risolto
Dopo sbattere la testa sul muro per un paio di giorni con questo problema, si era alla ricerca come il problema aveva a che fare con il tipo di contenuto negoziazione tra il client e il server. Ho scavato più in profondità che l'utilizzo di Fiddler per controllare i dettagli della richiesta provenienti dalla applicazione client, ecco uno screenshot della richiesta crudo come catturato dal violinista:

Fiddler capture of http request from client app

Ciò che ovviamente manca c'è l'intestazione Content-Type, anche se Lo stavo impostando come visto nell'esempio di codice nel mio post originale. Ho pensato che fosse strano che lo Content-Type non fosse mai arrivato anche se lo stavo impostando, quindi ho avuto un'altra occhiata al mio altro codice (funzionante) che chiamava un servizio API Web diverso, l'unica differenza era che stavo impostando la proprietà req.ContentType prima di scrivere al corpo della richiesta in quel caso. Ho apportato questa modifica a questo nuovo codice e l'ho fatto, il Content-Type ora stava mostrando e ho ottenuto la risposta di successo atteso dal servizio web. Il nuovo codice dal mio client .NET ora assomiglia a questo:

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" 

è tutto quello che era, la proprietà ContentType solo bisogno di essere impostata prima di scrivere al corpo della richiesta

Credo che questo comportamento è dovuto al fatto una volta che il contenuto viene scritto nel corpo viene trasmesso in streaming all'endpoint del servizio che viene chiamato, è necessario impostare qualsiasi altro attributo relativo alla richiesta prima di quello. Per favore correggimi se ho torto o se questo ha bisogno di maggiori dettagli.

12

Ho riscontrato questo problema quando ho chiamato il mio endpoint del servizio Web e l'ho risolto.

Nel mio caso si trattava di un problema nel modo in cui il client codificava il contenuto del corpo. Non stavo specificando la codifica o il tipo di supporto. Specificando loro risolto.

stavo facendo questo (causato 415 errore):

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

specificando la codifica e il tipo di supporto, ha funzionato:

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

Le stringhe magiche '' application/json ''sono disponibili come costanti ovunque in una libreria .NET Core? – CSJ

+1

@CSJ ce ne sono alcuni nello spazio dei nomi System.Net.Mime (ad es. System.Net.Mime.MediaTypeNames.Application.pdf fornisce "application/pdf") ma l'elenco non è completo e, per i nostri scopi specifici, fa non ne ha uno per "application/json" né fa parte della libreria core/standard. Vedi https://stackoverflow.com/questions/10362140/asp-mvc-are-there-any-constants-for-the-default-content-types - qualcuno ha gentilmente creato un elenco più completo di costanti. – monty