Aplicación POST de cadena a ASP.NET Web Api: devuelve nulo

Estoy tratando de transmitir una cadena desde el cliente a la aplicación ASP.NET MVC4.

Pero no puedo recibir la cadena, o es nula o no se puede encontrar el método de publicación (error 404)

Código de cliente para transmitir la cadena (aplicación de consola):

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(); 

Controlador Web Api de ASP.NET:

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

En ese caso, puedo llamar al método “Publicar”, pero “valor” es NULL . Si cambio la firma del método a (valor de cadena), nunca se llamará.

Incluso “sin” la configuración [Autorizar] tiene el mismo comportamiento extraño. -> Entonces no tiene nada que ver con la autenticación del usuario.

¿Alguna idea de lo que estoy haciendo mal? Estoy agradecido por cualquier ayuda.

Pareces haber usado algún atributo [Authorize] en tu acción de controlador Web API y no veo cómo esto es relevante para tu pregunta.

Entonces, pongámonos en práctica. A continuación, le mostramos cómo podría ser un controlador Web API trivial:

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

y un consumidor para ese asunto:

 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); } } } 

Sin duda, notará la decoración [FromBody] del atributo del controlador Web API así como el prefijo = de los datos POST del lado del cliente. Le recomendaría que lea acerca de cómo hace la API web vinculante de parámetros para comprender mejor los conceptos.

En lo que se refiere al atributo [Authorize] , esto podría usarse para proteger algunas acciones en su servidor para que no sean accesibles solo para los usuarios autenticados. En realidad, no está muy claro qué está tratando de lograr aquí. Por cierto, debió haber dejado esto más claro en su pregunta. ¿Está tratando de entender cómo funciona el enlace de parámetros en ASP.NET Web API (lea el artículo al que me he vinculado si este es su objective) o intenta realizar alguna autenticación y / o autorización? Si el segundo es su caso, puede encontrar la following post que escribí sobre este tema interesante para comenzar.

Y si después de leer los materiales con los que me he vinculado, eres como yo y te digo a ti mismo, WTF hombre, todo lo que necesito hacer es enviar una cadena a un extremo del servidor y tengo que hacer todo esto. De ninguna manera. Luego, compruebe ServiceStack . Tendrás una buena base para comparar con la API web. No sé en qué pensaban los tipos de Microsoft al diseñar la API web, pero vamos, en serio, deberíamos tener controladores base separados para nuestro HTML (piense en Razor) y cosas de REST. Esto no puede ser serio.

La API web funciona muy bien si acepta el hecho de que está utilizando HTTP. Es cuando comienzas a intentar fingir que estás enviando objetos por el cable que comienza a ensuciarse.

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

Este controlador manejará una solicitud HTTP, leerá una cadena de la carga y devolverá esa cadena.

Puede usar HttpClient para llamarlo pasando una instancia de StringContent. StringContent se usará por defecto text / plain como tipo de medio. Que es exactamente lo que estás tratando de pasar.

  [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); } 

Yo uso este código para publicar 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; } 

Con respecto a su código, pruébelo sin el contenido. Tipo ( request.ContentType = "application/x-www-form-urlencoded"; )

actualizar

Creo que el problema radica en cómo está tratando de recuperar el valor. Cuando realiza una POST y envía bytes a través de Stream, no se pasarán a la acción como parámetro. Tendrá que recuperar los bytes a través de la transmisión en el servidor.

En el servidor, intente obtener los bytes de la transmisión. El siguiente código es lo que 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; }