net - web api rest c#
AplicaciĆ³n POST de cadena a ASP.NET Web Api: devuelve nulo (7)
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);
}
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.
Para WebAPI, aquí está el código para recuperar el texto del cuerpo sin pasar por su enlace especial [Del Cuerpo].
public class YourController : ApiController
{
[HttpPost]
public HttpResponseMessage Post()
{
string bodyText = this.Request.Content.ReadAsStringAsync().Result;
//more code here...
}
}
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 objetivo) 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.
Por supuesto, Darrel sigue adelante con su respuesta. Una cosa para agregar es que la razón por la que intentas enlazar a un cuerpo que contiene un solo token como "hola".
es que no se trata de datos codificados en forma de URL. Al agregar "=" al frente de esta manera:
=hello
se convierte en una codificación de formulario URL de un único par de valores clave con un nombre y valor vacíos de "hola".
Sin embargo, una mejor solución es usar application / json al cargar una cadena:
POST /api/sample HTTP/1.1
Content-Type: application/json; charset=utf-8
Host: host:8080
Content-Length: 7
"Hello"
Usando HttpClient puedes hacerlo de la siguiente manera:
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.PostAsJsonAsync(_baseAddress + "api/json", "Hello");
string result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
Henrik
Yo uso este código para publicar HttpRequests.
/// <summary>
/// Post this message.
/// </summary>
/// <param name="url">URL of the document.</param>
/// <param name="bytes">The bytes.</param>
public T Post<T>(string url, byte[] bytes)
{
T item;
var request = WritePost(url, bytes);
using (var response = request.GetResponse() as HttpWebResponse)
{
item = DeserializeResponse<T>(response);
response.Close();
}
return item;
}
/// <summary>
/// Writes the post.
/// </summary>
/// <param name="url">The URL.</param>
/// <param name="bytes">The bytes.</param>
/// <returns></returns>
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.
/// <summary> Gets the body. </summary>
/// <returns> The body. </returns>
protected byte[] GetBytes()
{
byte[] bytes;
using (var binaryReader = new BinaryReader(Request.InputStream))
{
bytes = binaryReader.ReadBytes(Request.ContentLength);
}
return bytes;
}
me encuentro con este problema y encuentro este artículo. http://www.jasonwatmore.com/post/2014/04/18/Post-a-simple-string-value-from-AngularJS-to-NET-Web-API.aspx
La solución que encontré fue simplemente ajustar el valor de la cadena entre comillas dobles en su publicación js
¡Funciona de maravilla! FYI
([FromBody] IDictionary<string,object> data)