Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este tutorial se compila una aplicación que emite solicitudes HTTP a un servicio REST en GitHub. La aplicación lee información en formato JSON y convierte el JSON en objetos de C#. La conversión de JSON a objetos de C# se conoce como deserialización.
En el tutorial se muestra cómo:
- Enviar solicitudes HTTP.
- Deserializar las respuestas JSON.
- Configure la deserialización con atributos.
Si prefiere seguir el ejemplo final de este tutorial, puede descargarlo. Para obtener instrucciones de descarga, consulte Ejemplos y tutoriales.
Prerrequisitos
- La versión más reciente del SDK de .NET
- Editor de Visual Studio Code
- El DevKit de C#
Creación de la aplicación cliente
Abra un símbolo del sistema y cree un directorio para la aplicación. Haga que el directorio actual.
Escriba el siguiente comando en una ventana de consola:
dotnet new console --name WebAPIClientEste comando crea los archivos de inicio para una aplicación básica "Hola mundo". El nombre del proyecto es "WebAPIClient".
Vaya al directorio "WebAPIClient" y ejecute la aplicación.
cd WebAPIClientdotnet rundotnet runse ejecutadotnet restoreautomáticamente para restaurar las dependencias que la aplicación necesita. También se ejecutadotnet buildsi es necesario. Debería ver la salida"Hello, World!"de la aplicación. En el terminal, presione Ctrl+C para detener la aplicación.
Realización de solicitudes HTTP
Esta aplicación llama a la API de GitHub para obtener información sobre los proyectos en el paraguas de .NET Foundation . El punto de conexión es https://api.github.com/orgs/dotnet/repos. Para recuperar información, realiza una solicitud HTTP GET. Los exploradores también realizan solicitudes HTTP GET, por lo que puede pegar esa dirección URL en la barra de direcciones del explorador para ver qué información va a recibir y procesar.
Use la HttpClient clase para realizar solicitudes HTTP. HttpClient solo admite métodos asincrónicos para sus API de ejecución prolongada. Por lo tanto, los pasos siguientes crean un método asincrónico y lo llaman desde el método Main.
Abra el archivo en el directorio del
Program.csproyecto y reemplace su contenido por lo siguiente:await ProcessRepositoriesAsync(); static async Task ProcessRepositoriesAsync(HttpClient client) { }Este código:
- Reemplaza la
Console.WriteLineinstrucción por una llamada aProcessRepositoriesAsyncque usa laawaitpalabra clave . - Define un método vacío
ProcessRepositoriesAsync.
- Reemplaza la
En la
Programclase , use para HttpClient controlar las solicitudes y respuestas, reemplazando el contenido por el siguiente C#.using System.Net.Http.Headers; using HttpClient client = new(); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json")); client.DefaultRequestHeaders.Add("User-Agent", ".NET Foundation Repository Reporter"); await ProcessRepositoriesAsync(client); static async Task ProcessRepositoriesAsync(HttpClient client) { }Este código:
- Configura encabezados HTTP para todas las solicitudes:
- Encabezado
Acceptpara aceptar respuestas JSON - Encabezado
User-Agent. El código del servidor de GitHub comprueba estos encabezados y son necesarios para recuperar información de GitHub.
- Encabezado
- Configura encabezados HTTP para todas las solicitudes:
En el
ProcessRepositoriesAsyncmétodo , llame al punto de conexión de GitHub que devuelva una lista de todos los repositorios de la organización de .NET Foundation:static async Task ProcessRepositoriesAsync(HttpClient client) { var json = await client.GetStringAsync( "https://api.github.com/orgs/dotnet/repos"); Console.Write(json); }Este código:
- Espera la tarea devuelta desde el método de llamada HttpClient.GetStringAsync(String) . Este método envía una solicitud HTTP GET al URI especificado. El cuerpo de la respuesta se devuelve como , Stringque está disponible cuando se completa la tarea.
- La cadena
jsonde respuesta se imprime en la consola.
Compile la aplicación y ejecútelo.
dotnet runNo hay ninguna advertencia de compilación porque
ProcessRepositoriesAsyncahora contiene unawaitoperador . La salida es una presentación larga del texto JSON.
Deserializar el resultado JSON
Los pasos siguientes simplifican el enfoque para capturar los datos y procesarlos. Usará el GetFromJsonAsync método de extensión que forma parte del 📦 paquete NuGet System.Net.Http.Json para capturar y deserializar los resultados JSON en objetos.
Cree un archivo denominado Repository.cs y agregue el código siguiente:
public record class Repository(string Name);El código anterior define una clase para representar el objeto JSON devuelto desde la API de GitHub. Usará esta clase para mostrar una lista de nombres de repositorio.
El JSON de un objeto de repositorio contiene docenas de propiedades, pero solo se deserializará la
Namepropiedad. El serializador omite automáticamente las propiedades JSON para las que no hay ninguna coincidencia en la clase de destino. Esta característica facilita la creación de tipos que funcionan solo con un subconjunto de campos en un paquete JSON grande.Aunque el
GetFromJsonAsyncmétodo que usará en el siguiente punto tiene una ventaja de no distinguir entre mayúsculas y minúsculas cuando se trata de nombres de propiedad, la convención de C# es poner en mayúsculas la primera letra de los nombres de propiedad.Use el HttpClientJsonExtensions.GetFromJsonAsync método para capturar y convertir JSON en objetos de C#. Reemplace la llamada a GetStringAsync(String) en el
ProcessRepositoriesAsyncmétodo por las líneas siguientes:var repositories = await client.GetFromJsonAsync<List<Repository>>("https://api.github.com/orgs/dotnet/repos");El código actualizado reemplaza GetStringAsync(String) por HttpClientJsonExtensions.GetFromJsonAsync.
El primer argumento para
GetFromJsonAsyncel método es unaawaitexpresión.awaitLas expresiones pueden aparecer casi en cualquier parte del código, aunque hasta ahora solo las haya visto como parte de una instrucción de asignación. El siguiente parámetro esrequestUriopcional y no tiene que proporcionarse si ya se especificó al crear elclientobjeto. No proporcionó elclientobjeto con el URI al que enviar la solicitud, por lo que especificó el URI ahora. El último parámetro opcional,CancellationTokense omite en el fragmento de código.El
GetFromJsonAsyncmétodo es genérico, lo que significa que se proporcionan argumentos de tipo para qué tipo de objetos se deben crear a partir del texto JSON capturado. En este ejemplo, va a deserializar en unList<Repository>objeto , que es otro objeto genérico, un System.Collections.Generic.List<T>. LaList<T>clase almacena una colección de objetos . El argumento type declara el tipo de objetos almacenados en .List<T>El argumento type es elRepositoryregistro, ya que el texto JSON representa una colección de objetos de repositorio.Agregue código para mostrar el nombre de cada repositorio. Reemplace las líneas que leen:
Console.Write(json);con el código siguiente:
foreach (var repo in repositories ?? Enumerable.Empty<Repository>()) Console.WriteLine(repo.Name);Las siguientes
usingdirectivas deben estar presentes en la parte superior del archivo:using System.Net.Http.Headers; using System.Net.Http.Json;Ejecute la aplicación.
dotnet runLa salida es una lista de los nombres de los repositorios que forman parte de .NET Foundation.
Refactorización del código
El ProcessRepositoriesAsync método puede realizar el trabajo asincrónico y devolver una colección de los repositorios. Cambie ese método para devolver Task<List<Repository>>y mueva el código que escribe en la consola cerca de su autor de llamada.
Cambie la firma de
ProcessRepositoriesAsyncpara devolver una tarea cuyo resultado es una lista deRepositoryobjetos:static async Task<List<Repository>> ProcessRepositoriesAsync(HttpClient client)Devuelve los repositorios después de procesar la respuesta JSON:
var repositories = await client.GetFromJsonAsync<List<Repository>>("https://api.github.com/orgs/dotnet/repos"); return repositories ?? new();El compilador genera el
Task<T>objeto para el valor devuelto porque ha marcado este método comoasync.Modifique el archivo Program.cs , reemplazando la llamada a
ProcessRepositoriesAsyncpor lo siguiente para capturar los resultados y escribir cada nombre de repositorio en la consola.var repositories = await ProcessRepositoriesAsync(client); foreach (var repo in repositories) Console.WriteLine(repo.Name);Ejecute la aplicación.
La salida es la misma.
Deserializar más propiedades
En los pasos siguientes, ampliamos el código para procesar más propiedades de la carga JSON devuelta por la API de GitHub. Probablemente no tendrá que procesar todas las propiedades, pero agregar algunas muestran características adicionales de C#.
Reemplace el contenido de la
Repositoryclase por la siguienterecorddefinición. Asegúrese de importar elSystem.Text.Json.Serializationespacio de nombres y aplicar el[JsonPropertyName]atributo para asignar campos JSON a propiedades de C# explícitamente.using System.Text.Json.Serialization; public record class Repository( string Name, string Description, [property: JsonPropertyName("html_url")] Uri GitHubHomeUrl, Uri Homepage, int Watchers, [property: JsonPropertyName("pushed_at")] DateTime LastPushUtc );Los Uri tipos y
inttienen funcionalidad integrada para convertir a y desde la representación de cadena. No se necesita código adicional para deserializar desde el formato de cadena JSON a esos tipos de destino. Si el paquete JSON contiene datos que no se convierten en un tipo de destino, la acción de serialización produce una excepción.JSON suele usar
lowercaseosnake_casepara nombres de propiedad. Los campos comohtml_urlypushed_atno siguen las convenciones de nomenclatura de PascalCase de C#. El uso de[JsonPropertyName]garantiza que estas claves JSON estén enlazadas correctamente a sus propiedades de C# correspondientes, incluso cuando sus nombres difieren en el uso de mayúsculas o contienen caracteres de subrayado. Este enfoque garantiza la deserialización predecible y estable, al tiempo que permite nombres de propiedad PascalCase en C#. Además, el métodoGetFromJsonAsyncescase-insensitiveal coincidir con los nombres de propiedad, por lo que no es necesaria ninguna conversión adicional.Actualice el
foreachbucle en el archivo Program.cs para mostrar los valores de propiedad:foreach (var repo in repositories) { Console.WriteLine($"Name: {repo.Name}"); Console.WriteLine($"Homepage: {repo.Homepage}"); Console.WriteLine($"GitHub: {repo.GitHubHomeUrl}"); Console.WriteLine($"Description: {repo.Description}"); Console.WriteLine($"Watchers: {repo.Watchers:#,0}"); Console.WriteLine(); }Ejecute la aplicación.
La lista ahora incluye las propiedades adicionales.
Agregar una propiedad date
La fecha de la última operación de inserción tiene el formato de esta manera en la respuesta JSON:
2016-02-08T21:27:00Z
Este formato es para hora universal coordinada (UTC), por lo que el resultado de la deserialización es un DateTime valor cuya Kind propiedad es Utc.
Para obtener una fecha y hora representadas en la zona horaria, debe escribir un método de conversión personalizado.
En Repository.cs, agregue una propiedad para la representación UTC de la fecha y hora y una propiedad readonly
LastPushque devuelva la fecha convertida a la hora local, el archivo debe tener un aspecto similar al siguiente:using System.Text.Json.Serialization; public record class Repository( string Name, string Description, [property: JsonPropertyName("html_url")] Uri GitHubHomeUrl, Uri Homepage, int Watchers, [property: JsonPropertyName("pushed_at")] DateTime LastPushUtc ) { public DateTime LastPush => LastPushUtc.ToLocalTime(); }La
LastPushpropiedad se define mediante un miembro con forma de expresión para el descriptor degetacceso. No hay ningúnsetdescriptor de acceso. Omitir elsetdescriptor de acceso es una manera de definir una propiedad de solo lectura en C#. (Sí, puede crear propiedades de solo escritura en C#, pero su valor es limitado).Agregue otra instrucción de salida en Program.cs: de nuevo:
Console.WriteLine($"Last push: {repo.LastPush}");La aplicación completa debe ser similar al siguiente archivo Program.cs :
using System.Net.Http.Headers; using System.Net.Http.Json; using HttpClient client = new(); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json")); client.DefaultRequestHeaders.Add("User-Agent", ".NET Foundation Repository Reporter"); var repositories = await ProcessRepositoriesAsync(client); foreach (var repo in repositories) { Console.WriteLine($"Name: {repo.Name}"); Console.WriteLine($"Homepage: {repo.Homepage}"); Console.WriteLine($"GitHub: {repo.GitHubHomeUrl}"); Console.WriteLine($"Description: {repo.Description}"); Console.WriteLine($"Watchers: {repo.Watchers:#,0}"); Console.WriteLine($"{repo.LastPush}"); Console.WriteLine(); } static async Task<List<Repository>> ProcessRepositoriesAsync(HttpClient client) { var repositories = await client.GetFromJsonAsync<List<Repository>>("https://api.github.com/orgs/dotnet/repos"); return repositories ?? new List<Repository>(); }Ejecute la aplicación.
La salida incluye la fecha y hora de la última inserción en cada repositorio.
Pasos siguientes
En este tutorial, ha creado una aplicación que realiza solicitudes web y analiza los resultados. La versión de la aplicación debe coincidir ahora con el ejemplo terminado.
Obtenga más información sobre cómo configurar la serialización JSON en Cómo serializar y deserializar (serializar y deserializar) JSON en .NET.