Consumiendo el API en otra APP de Windows Forms - jcpichardo/Progra-II GitHub Wiki
En esta aplicación creen dos carpetas Model y Service.
En model va la clase estudiantes y la clase persona estas son iguales a las que ya creamos en las clases pasadas. Aqui no agregamos la biblioteca de clases por que esta proyecto es la SIMULACIÓN DE OTRO PROYECTO TOTALMENTE INDEPENDIENTE AL NUESTRO.
En la carpeta de Service crean la clase Api Service.
using ControlEscolarCore.Model;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Net.Http;
using System.Threading.Tasks;
public class ApiService
{
private readonly HttpClient _httpClient;
// Obtener la URL desde el archivo configuración
private readonly string _baseUrl = ConfigurationManager.AppSettings["ApiBaseUrl"] ?? throw new InvalidOperationException("La clave 'ApiBaseUrl' no está configurada en AppSettings.");
public ApiService()
{
_httpClient = new HttpClient();
_httpClient.Timeout = TimeSpan.FromSeconds(30);
}
public async Task<List<Estudiante>> GetEstudiantesAsync(bool soloActivos = true,
int tipoFecha = 2,
DateTime? fechaInicio = null,
DateTime? fechaFin = null)
{
try
{
string endpoint = "estudiantescontrollerapi_test/list_estudiantes";
string queryString = $"?soloActivos={soloActivos}&tipoFecha={tipoFecha}";
if (fechaInicio.HasValue)
queryString += $"&fechaInicio={fechaInicio.Value:yyyy-MM-dd}";
if (fechaFin.HasValue)
queryString += $"&fechaFin={fechaFin.Value:yyyy-MM-dd}";
HttpResponseMessage response = await _httpClient.GetAsync(_baseUrl + endpoint + queryString);
if (response.IsSuccessStatusCode)
{
string json = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<List<Estudiante>>(json);
}
else
{
// Manejar errores
string errorContent = await response.Content.ReadAsStringAsync();
throw new Exception($"Error al obtener estudiantes: {response.StatusCode} - {errorContent}");
}
}
catch (Exception ex)
{
// Loguear y relanzar la excepción
Console.WriteLine($"Error en API: {ex.Message}");
throw;
}
}
}
Este clase consumira el API que publicamos
En el archivo de confuración creen una variable para consumir nuestra URL base que por lo general no cambiara y es la base de nuestra API
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="ApiBaseUrl" value="https://controlescolar-api-test.onrender.com/api/" />
</appSettings>
</configuration>
En una ventana de windows forms creen un data grid view y un boton
using System;
using System.Configuration;
namespace ConsumiendoAPI_Test
{
public partial class Form1 : Form
{
private readonly ApiService _apiService;
public Form1()
{
InitializeComponent();
_apiService = new ApiService();
}
private void Form1_Load(object sender, EventArgs e)
{
Consulta();
}
private async void Consulta()
{
try
{
Cursor = Cursors.WaitCursor;
var estudiantes = await _apiService.GetEstudiantesAsync(true, 2, DateTime.Parse("01/01/2025"), DateTime.Parse("10/05/2025"));
// Mostrar resultados
dataGridView1.DataSource = estudiantes;
}
catch (Exception ex)
{
MessageBox.Show($"Error al consultar estudiantes: {ex.Message}");
}
finally
{
Cursor = Cursors.Default;
}
}
private void button1_Click(object sender, EventArgs e)
{
Consulta();
}
}
}
En esta ventana consumimos nuestra clase APIService para poblar la lista de estudiantes
- En el Controller de Estudiante creamos una funcion especial para solo actualizar el nombre
public (bool exito, string mensaje) ActualizarNombreEstudiante(int idestudiante, string nuevo_nombre)
{
try
{
// Verificar si el estudiante existe
Estudiante? estudianteExistente = _estudiantesData.ObtenerEstudiantePorId(idestudiante);
if (estudianteExistente == null)
{
return (false, $"No se encontró el estudiante con ID {idestudiante}");
}
estudianteExistente.DatosPersonales.NombreCompleto = nuevo_nombre;
bool resultado = _estudiantesData.ActualizarEstudiante(estudianteExistente);
if (!resultado)
{
_logger.Error($"Error al actualizar el estudiante con ID {idestudiante}");
return (false, "Error al actualizar el estudiante en la base de datos");
}
_logger.Info($"Estudiante con ID {idestudiante} actualizado exitosamente");
return (true, "Estudiante actualizado exitosamente");
}
catch (Exception ex)
{
_logger.Error(ex, $"Error inesperado al actualizar estudiante con ID {idestudiante}");
return (false, $"Error inesperado: {ex.Message}");
}
}
- En nuestro proyecto WEB API creamos el IActionResult que vamos a exponer
/// <summary>
/// Actualiza los datos de un estudiante existente.
/// </summary>
/// <param name="idestudiante">Identificador del estudiante</param>
/// <returns>Resultado de la operación</returns>
[HttpPut("actualizar_nombreestudiante")]
public IActionResult ActualizarEstudiante([FromQuery]int idestudiante, [FromQuery] string nuevo_nombre)
{
try
{
var resultado = _estudiantesController.ActualizarNombreEstudiante(idestudiante, nuevo_nombre);
if (resultado.exito)
return Ok(new { mensaje = resultado.mensaje });
else
return BadRequest(new { mensaje = resultado.mensaje });
}
catch (Exception ex)
{
_logger.LogError(ex, "Error al actualizar estudiante");
return StatusCode(500, "Error interno del servidor: " + ex.Message);
}
}
- Revisen bien que ahora es [HttpPut("actualizar_nombreestudiante")]
- En la anterior funcion fue GET por que obtenemos datos, pero si queremos insertar o acutualizar la funcion es PUT
- Compilar, hacer un commit en GIT y hacen Deploy del API en Render
- Creen una nueva ventana del proyecto en Windows Forms que tenemos por separado y llamen a la nueva fuincion del API.
NOTA yo use el ID para mostrarles el ejemplo rapido, ustedes pueden usar el numero de matricula.
- Codigo de consumo en APISerivice
public async Task<(bool exito, string mensaje)> ActualizarEstudianteAsync(int idestudiante, string nuevo_nombre)
{
try
{
// Asegurarse de codificar el nombre correctamente en la URL
string nuevoNombreEncoded = Uri.EscapeDataString(nuevo_nombre);
// Construir la URL con ambos parámetros en query string
string endpoint = $"estudiantescontrollerapi_test/actualizar_nombreestudiante?idestudiante={idestudiante}&nuevo_nombre={nuevoNombreEncoded}";
// Enviar PUT sin contenido en el body
var request = new HttpRequestMessage(HttpMethod.Put, _baseUrl + endpoint);
HttpResponseMessage response = await _httpClient.SendAsync(request);
string responseContent = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var resultado = JsonConvert.DeserializeObject<dynamic>(responseContent);
return (true, resultado?.mensaje?.ToString() ?? "Estudiante actualizado con éxito");
}
else
{
var resultado = JsonConvert.DeserializeObject<dynamic>(responseContent);
string mensajeError = resultado?.mensaje?.ToString() ?? "Error al actualizar estudiante";
return (false, mensajeError);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error en API al actualizar estudiante: {ex.Message}");
return (false, $"Error inesperado: {ex.Message}");
}
}
- Consumo en Windows Forms
public async void LlamarActualizarEstudiante()
{
int id = int.Parse(txtID.Text); // Suponiendo que tienes un TextBox llamado txtIdEstudiante
string nuevoNombre = txtNuevoNombre.Text; // Suponiendo que tienes un TextBox llamado txtNuevoNombre
var resultado = await _apiService.ActualizarEstudianteAsync(id, nuevoNombre); // Servicio donde tienes el método async
if (resultado.exito)
{
MessageBox.Show(resultado.mensaje, "Éxito", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show(resultado.mensaje, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}