¿Enviar JSON a través de POST en C # y recibir el JSON devuelto?

86

Esta es la primera vez que uso JSON System.Nety WebRequesten cualquiera de mis aplicaciones. Se supone que mi aplicación envía una carga útil JSON, similar a la que se muestra a continuación, a un servidor de autenticación:

{
  "agent": {                             
    "name": "Agent Name",                
    "version": 1                                                          
  },
  "username": "Username",                                   
  "password": "User Password",
  "token": "xxxxxx"
}

Para crear esta carga útil, utilicé la JSON.NETbiblioteca. ¿Cómo enviaría estos datos al servidor de autenticación y recibiría su respuesta JSON? Esto es lo que he visto en algunos ejemplos, pero sin contenido JSON:

var http = (HttpWebRequest)WebRequest.Create(new Uri(baseUrl));
http.Accept = "application/json";
http.ContentType = "application/json";
http.Method = "POST";

string parsedContent = "Parsed JSON Content needs to go here";
ASCIIEncoding encoding = new ASCIIEncoding();
Byte[] bytes = encoding.GetBytes(parsedContent);

Stream newStream = http.GetRequestStream();
newStream.Write(bytes, 0, bytes.Length);
newStream.Close();

var response = http.GetResponse();

var stream = response.GetResponseStream();
var sr = new StreamReader(stream);
var content = sr.ReadToEnd();

Sin embargo, esto parece ser mucho código comparado con el uso de otros lenguajes que he usado en el pasado. ¿Estoy haciendo esto correctamente? ¿Y cómo obtendría la respuesta JSON para poder analizarla?

Gracias, Elite.

Código actualizado

// Send the POST Request to the Authentication Server
// Error Here
string json = await Task.Run(() => JsonConvert.SerializeObject(createLoginPayload(usernameTextBox.Text, password)));
var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
using (var httpClient = new HttpClient())
{
    // Error here
    var httpResponse = await httpClient.PostAsync("URL HERE", httpContent);
    if (httpResponse.Content != null)
    {
        // Error Here
        var responseContent = await httpResponse.Content.ReadAsStringAsync();
    }
}
Hunter Mitchell
fuente
2
Puede intentarlo WebClient.UploadString(JsonConvert.SerializeObjectobj(yourobj))oHttpClient.PostAsJsonAsync
LB

Respuestas:

129

Me encontré usando HttpClient biblioteca para consultar las API RESTful ya que el código es muy sencillo y completamente asincrónico.

(Editar: Agregar JSON de la pregunta para mayor claridad)

{
  "agent": {                             
    "name": "Agent Name",                
    "version": 1                                                          
  },
  "username": "Username",                                   
  "password": "User Password",
  "token": "xxxxxx"
}

Con dos clases que representan la estructura JSON que publicó, que puede verse así:

public class Credentials
{
    [JsonProperty("agent")]
    public Agent Agent { get; set; }

    [JsonProperty("username")]
    public string Username { get; set; }

    [JsonProperty("password")]
    public string Password { get; set; }

    [JsonProperty("token")]
    public string Token { get; set; }
}

public class Agent
{
    [JsonProperty("name")]
    public string Name { get; set; }

    [JsonProperty("version")]
    public int Version { get; set; }
}

podría tener un método como este, que haría su solicitud POST:

var payload = new Credentials { 
    Agent = new Agent { 
        Name = "Agent Name",
        Version = 1 
    },
    Username = "Username",
    Password = "User Password",
    Token = "xxxxx"
};

// Serialize our concrete class into a JSON String
var stringPayload = await Task.Run(() => JsonConvert.SerializeObject(payload));

// Wrap our JSON inside a StringContent which then can be used by the HttpClient class
var httpContent = new StringContent(stringPayload, Encoding.UTF8, "application/json");

using (var httpClient = new HttpClient()) {

    // Do the actual request and await the response
    var httpResponse = await httpClient.PostAsync("http://localhost/api/path", httpContent);

    // If the response contains content we want to read it!
    if (httpResponse.Content != null) {
        var responseContent = await httpResponse.Content.ReadAsStringAsync();

        // From here on you could deserialize the ResponseContent back again to a concrete C# type using Json.Net
    }
}
Kai Eichinger
fuente
5
perfecto, pero ¿cuál es la espera Task.run (()?
Hunter Mitchell
21
¡No debe usar Task.Run en métodos vinculados a CPU síncronos ya que solo está disparando un nuevo hilo sin ningún beneficio!
Stephen Foster
2
No es necesario que escriba el JsonPropertypara cada propiedad. Simplemente use el CamelCasePropertyNamesContractResolver integrado de Json.Net o un personalizadoNamingStrategy para personalizar el proceso de serialización
Seafish
6
Nota al margen: no use usingcon HttpClient. Ver: aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
maxshuty
4
Con System.Net.Http.Formatting, tiene métodos de extensión definidos: "await httpClient.PostAsJsonAsync (" api / v1 / domain ", csObjRequest)"
hB0
13

Con el paquete JSON.NET NuGet y los tipos anónimos, puede simplificar lo que sugieren los otros carteles:

// ...

string payload = JsonConvert.SerializeObject(new
{
    agent = new
    {
        name    = "Agent Name",
        version = 1,
    },

    username = "username",
    password = "password",
    token    = "xxxxx",
});

var client = new HttpClient();
var content = new StringContent(payload, Encoding.UTF8, "application/json");

HttpResponseMessage response = await client.PostAsync(uri, content);

// ...
Maximilian Burszley
fuente
6

Puede construir su HttpContentusando la combinación de JObjectpara evitar JPropertyy luego invocarlo ToString()cuando construya StringContent:

        /*{
          "agent": {                             
            "name": "Agent Name",                
            "version": 1                                                          
          },
          "username": "Username",                                   
          "password": "User Password",
          "token": "xxxxxx"
        }*/

        JObject payLoad = new JObject(
            new JProperty("agent", 
                new JObject(
                    new JProperty("name", "Agent Name"),
                    new JProperty("version", 1)
                    ),
                new JProperty("username", "Username"),
                new JProperty("password", "User Password"),
                new JProperty("token", "xxxxxx")    
                )
            );

        using (HttpClient client = new HttpClient())
        {
            var httpContent = new StringContent(payLoad.ToString(), Encoding.UTF8, "application/json");

            using (HttpResponseMessage response = await client.PostAsync(requestUri, httpContent))
            {
                response.EnsureSuccessStatusCode();
                string responseBody = await response.Content.ReadAsStringAsync();
                return JObject.Parse(responseBody);
            }
        }
Jan Dolejsi
fuente
¿Cómo evitas los Exception while executing function. Newtonsoft.Json: Can not add Newtonsoft.Json.Linq.JProperty to Newtonsoft.Json.Linq.JArrayerrores?
Jari Turkia
1
No se supone que una instancia de HttpClient se cree con el uso de construct. La instancia debe crearse una vez y usarse en toda la aplicación. Esto se debe a que utiliza su propio grupo de conexiones. Su código tiende principalmente a lanzar SocketException. docs.microsoft.com/en-us/dotnet/api/…
Harun Diluka Heshan
2

También puede utilizar el método PostAsJsonAsync () disponible en HttpClient ()

   var requestObj= JsonConvert.SerializeObject(obj);
   HttpResponseMessage response = await    client.PostAsJsonAsync($"endpoint",requestObj).ConfigureAwait(false);

Rukshala Weerasinghe
fuente
1
¿Puede agregar una explicación de lo que hace su código y cómo resuelve el problema?
Nilambar Sharma
Puede tomar cualquier objeto que desee publicar y serializarlo usando SerializeObject (); var obj= new Credentials { Agent = new Agent { Name = "Agent Name", Version = 1 }, Username = "Username", Password = "User Password", Token = "xxxxx" }; Y luego, sin tener que convertirlo a httpContent, puede usar PostAsJsonAsync () pasando la URL del extremo y el propio objeto JSON convertido.
Rukshala Weerasinghe