Stringa POST su ASP.NET Applicazione Web API – restituisce null

Sto cercando di trasmettere una stringa dal client all’applicazione ASP.NET MVC4.

Ma non riesco a ricevere la stringa, o è null o il metodo post non può essere trovato (errore 404)

Codice client per trasmettere la stringa (Applicazione Console):

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:49032/api/test"); request.Credentials = new NetworkCredential("user", "pw"); request.Method = "POST"; string postData = "Short test..."; byte[] byteArray = Encoding.UTF8.GetBytes(postData); request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = byteArray.Length; Stream dataStream = request.GetRequestStream(); dataStream.Write(byteArray, 0, byteArray.Length); dataStream.Close(); WebResponse response = request.GetResponse(); Console.WriteLine(((HttpWebResponse)response).StatusDescription); dataStream = response.GetResponseStream(); StreamReader reader = new StreamReader(dataStream); string responseFromServer = reader.ReadToEnd(); Console.WriteLine(responseFromServer); reader.Close(); dataStream.Close(); response.Close(); Console.ReadLine(); 

Controller Api Web ASP.NET:

 public class TestController : ApiController { [Authorize] public String Post(byte[] value) { return value.Length.ToString(); } } 

In tal caso, sono in grado di chiamare il metodo “Post”, ma “value” è NULL . Se cambio la firma del metodo su (valore stringa) di quella che non chiamerà mai.

Anche “senza” l’impostazione [Autorizza] ha lo stesso strano comportamento. -> Quindi non ha nulla a che fare con l’autenticazione dell’utente.

Qualche idea su cosa sto facendo male? Sono grato per qualsiasi aiuto.

Sembra che tu abbia usato qualche attributo [Authorize] sull’azione del controller API Web e non vedo come questo sia pertinente alla tua domanda.

Quindi, entriamo in pratica. Ecco come potrebbe apparire un controller API Web banale:

 public class TestController : ApiController { public string Post([FromBody] string value) { return value; } } 

e un consumatore per quella materia:

 class Program { static void Main() { using (var client = new WebClient()) { client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded"; var data = "=Short test..."; var result = client.UploadString("http://localhost:52996/api/test", "POST", data); Console.WriteLine(result); } } } 

Noterai senza dubbio la decorazione [FromBody] dell’attributo del controller API Web e il prefisso = dei dati POST sul lato client. Ti consiglierei di leggere su come l’API Web esegue il binding dei parametri per comprendere meglio i concetti.

Per quanto riguarda l’attributo [Authorize] , questo potrebbe essere usato per proteggere alcune azioni sul tuo server dall’essere accessibili solo agli utenti autenticati. In realtà non è abbastanza chiaro cosa stai cercando di ottenere qui. Avresti dovuto renderlo più chiaro nella tua domanda, a proposito. Stai cercando di capire come funziona il binding dei parametri nell’API Web di ASP.NET (leggi l’articolo a cui mi sono collegato se questo è il tuo objective) o stai tentando di eseguire un’autenticazione e / o un’authorization? Se il secondo è il tuo caso, potresti trovare il following post che ho scritto su questo argomento interessante per iniziare.

E se dopo aver letto i materiali a cui mi sono collegato, sei come me e dici a te stesso, WTF man, tutto quello che devo fare è POST una stringa per un endpoint lato server e devo fare tutto questo? Non c’è modo. Quindi checkout ServiceStack . Avrai una buona base per il confronto con l’API Web. Non so a cosa stessero pensando i ragazzi di Microsoft quando progettavano l’API Web, ma dai, dovremmo avere controller di base separati per il nostro HTML (pensi Razor) e roba REST? Questo non può essere serio.

L’API Web funziona molto bene se si accetta il fatto che si stia utilizzando HTTP. È quando inizi a provare a fingere di inviare oggetti sul filo che inizia a diventare disordinato.

  public class TextController : ApiController { public HttpResponseMessage Post(HttpRequestMessage request) { var someText = request.Content.ReadAsStringAsync().Result; return new HttpResponseMessage() {Content = new StringContent(someText)}; } } 

Questo controller gestirà una richiesta HTTP, leggerà una stringa dal payload e restituirà quella stringa.

È ansible utilizzare HttpClient per chiamarlo passando un’istanza di StringContent. StringContent sarà di default usa text / plain come tipo di media. Che è esattamente quello che stai cercando di passare.

  [Fact] public void PostAString() { var client = new HttpClient(); var content = new StringContent("Some text"); var response = client.PostAsync("http://oak:9999/api/text", content).Result; Assert.Equal("Some text",response.Content.ReadAsStringAsync().Result); } 

Io uso questo codice per pubblicare HttpRequests.

 ///  /// Post this message. ///  /// URL of the document. /// The bytes. public T Post(string url, byte[] bytes) { T item; var request = WritePost(url, bytes); using (var response = request.GetResponse() as HttpWebResponse) { item = DeserializeResponse(response); response.Close(); } return item; } ///  /// Writes the post. ///  /// The URL. /// The bytes. ///  private static HttpWebRequest WritePost(string url, byte[] bytes) { ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true; HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url); Stream stream = null; try { request.Headers.Clear(); request.PreAuthenticate = true; request.Connection = null; request.Expect = null; request.KeepAlive = false; request.ContentLength = bytes.Length; request.Timeout = -1; request.Method = "POST"; stream = request.GetRequestStream(); stream.Write(bytes, 0, bytes.Length); } catch (Exception e) { GetErrorResponse(url, e); } finally { if (stream != null) { stream.Flush(); stream.Close(); } } return request; } 

Per quanto riguarda il tuo codice, provalo senza content.Type ( request.ContentType = "application/x-www-form-urlencoded"; )

aggiornare

Credo che il problema risieda nel modo in cui stai cercando di recuperare il valore. Quando si esegue un POST e si inviano byte tramite Stream, questi non verranno passati all’azione come parametro. Dovrai recuperare i byte tramite lo streaming sul server.

Sul server, prova a ottenere i byte dallo stream. Il seguente codice è quello che uso.

  ///  Gets the body.  ///  The body.  protected byte[] GetBytes() { byte[] bytes; using (var binaryReader = new BinaryReader(Request.InputStream)) { bytes = binaryReader.ReadBytes(Request.ContentLength); } return bytes; } 

Darrel ha ovviamente ragione con la sua risposta. Una cosa da aggiungere è che il motivo per cui si tenta di legarsi a un corpo contenente un singolo token come “ciao”.

è che non si tratta di dati codificati in forma di URL. Aggiungendo “=” davanti in questo modo:

 =hello 

diventa una codifica del modulo URL di una singola coppia di valori chiave con un nome vuoto e il valore di “ciao”.

Tuttavia, una soluzione migliore è usare application / json quando si carica una stringa:

 POST /api/sample HTTP/1.1 Content-Type: application/json; charset=utf-8 Host: host:8080 Content-Length: 7 "Hello" 

Usando HttpClient puoi farlo come segue:

 HttpClient client = new HttpClient(); HttpResponseMessage response = await client.PostAsJsonAsync(_baseAddress + "api/json", "Hello"); string result = await response.Content.ReadAsStringAsync(); Console.WriteLine(result); 

Henrik

Per WebAPI, qui è il codice per recuperare il testo del corpo senza passare attraverso il binding speciale [FromBody].

 public class YourController : ApiController { [HttpPost] public HttpResponseMessage Post() { string bodyText = this.Request.Content.ReadAsStringAsync().Result; //more code here... } } 

ho incontrato questo problema e ho trovato questo articolo http://www.jasonwatmore.com/post/2014/04/18/Post-a-simple-string-value-from-AngularJS-to-NET-Web-API.aspx

La soluzione che ho trovato era semplicemente racchiudere il valore della stringa tra virgolette nel tuo post js

funziona come un fascino! FYI

 ([FromBody] IDictionary data)