API - jcpichardo/Progra-II GitHub Wiki
Actualmente tenemos un proyecto de Windows Forms, el cual no es compatible con un proyecto Web y debemos considerar que dentro de nuestros controller tenemos las funciones que debemos exponer públicamente en la web.
Comenzaremos con separar el proyecto de la siguiente manera:
- Aplicación Windows Forms
- Biblioteca de clases (todo el backend, Controllers, Data, PostgresSQLDataAcces)
Nuestra aplicación windows forms, ahora consumirá todo a través de esta biblioteca de clases
- Agregamos un proyecto de biblioteca de clases
- Lo llamaremos ControlEscolarCore
- Borramos la clase predeterminada que se creo.
- Vamos a mover los siguientes capas a ControlEscolarCore
Nuesto proyecto ahora debe quedar estructurado de la siguiente manera:
ControlEscolarCore es nuestra biblioteca de clases y aqui tenemos todo el backend, exportable a cualquier proyecto.
Recompilamos la solución y vemos que tenemos muchos errores ya que ahora tenemos que llamar todo el backend de la biblioteca de clases
Muchos errores de la compilación son porque nuestro proyecto ControlEscolarCore no tiene instalados los paquetes Nuget.
El siguiente paso sera cambiar el nombre del namespace a todas las clases de nuestra biblioteca de clases
Apuntamos a los nuevos nombres y compilamos nuestra biblioteca de clases.
EL OBJETIVO ES COMPILAR SIN ERRORES NUESTRA BILBLIOTECA DE CLAES PARA LLAMARLA EN NUESTRO PROYECTO EN LA VISTA
Un error importante se da tambien al no detectar el objeto ConfigurationManager

Instalemos el nuget en el proyecto.

CON ESTO QUEDA COMPILADO DE MANERA CORRECTA NUESTA BIBLIOTECA DE CLASES
Intentamos compilar la aplicación Widows Forma y observamos que tiene ERRORES por que no existe ningun objeto del backend
Para resolver este problema, realizaremos lo siguiente
- Incluiremos como referencia nuestra biblioteca de clases.



- Renombrar los Using

- Las clases que son Internal tendran que cambiar a Public

- Corregir todos los errores que se presenten apuntando a la biblioteca de clases.
LA APLICACIÓN DEBE CORRER Y FUNCIONAR DE MANERA CORRECTA ESTRUCTURADA DE LA SIGUIENTE MANERA.

- Creamos un nuevo proyecto dentro de nuestra solución

- Creamos un proyecto de Web API

- Colocamos un nombre


- Agregamos la clase del controlador API que contendra las funciones que vamos a exponer en la WEB

- Nuestro nuevo controlador nos quedo de la siguiente manera.

- Al igual que en nuestro proyecto de Windows Form, en este proyecto WEB tambien agregaremos una referencia al proyecto, y será nuestra biblioteca de clases.

- Buscamos la biblioteca de clases

- El proyecto debe de quedar de la siguiente manera

- Agregamos los namespace que ocuparemos en el API WEB, asi como atributos que definiran el comportamiento de nuestra WEB API

- Declaramos dos objetos

- Declaramos el constructor
public EstudiantesControllerAPI_test(EstudiantesController estudiantesController, ILogger<EstudiantesControllerAPI_test> logger)
{
_estudiantesController = estudiantesController;
_logger = logger;
}
- En nuestra clase heredaremos de ControllerBase que ya nos brinda respuestas HTTP
public class EstudiantesControllerAPI_test : ControllerBase


- Finalmente creamos nuestra función que devolvera los estudiantes, trabajando con los controllers que hicimos en nuestro proyecto de la biblioteca de clases.

-
Agregar dos archivos necesarios para publicar en Render.
-
.dockerignore

- Agregamos un nuevo elemento al proyecto, seleccionamos archivo de texto y lo nombramos tal cual esta en el paso 2.
# Archivos y carpetas generales a ignorar
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/bin
**/obj
**/charts
**/docker-compose*
**/compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/secrets.dev.yaml
**/values.dev.yaml
README.md
# Ignorar específicamente el proyecto Windows Forms
ControlEscolar/
ControlEscolar.Tests/
# Cualquier otro proyecto específico de Windows que no sea necesario para la API
# Ignorar archivos de desarrollo
**/*.user
**/*.suo
-
Dockerfile
-
Abrimos la carpeta donde se encuentra la solución del proyecto.
-
Creamos un archivo sin extensión llamado Dockerfile, abrimos un notepad y creamos un archivo con este nombre entre comillas
Contenido del archivo
# Etapa de construcción
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /app
# Copiar toda la solución primero
COPY . ./
# Listar los directorios para depuración
RUN ls -la
# Intentar construir solo el proyecto API
RUN find . -name "API_Estudiantes_Test.csproj" -exec dotnet publish {} -c Release -o /app/out \;
# Si lo anterior falla, intentar buscar la API por nombre
RUN if [ ! -d /app/out ]; then \
find . -name "*.csproj" | grep -i api | xargs -I {} dotnet publish {} -c Release -o /app/out; \
fi
# Etapa final
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app/out .
EXPOSE 80
EXPOSE 443
# Buscar el nombre exacto del DLL de la API
RUN find . -name "*.dll" | grep -i api
# Entrypoint dinámico que busca el archivo API.dll
ENTRYPOINT ["sh", "-c", "dotnet $(find . -name \"*API.dll\" | head -1)"]
-
Subir el proyecto del Web Api a Git con la misma cuenta que tenemos el registro en render
-
Abrimos nuestra cuenta en Render y creamos un nuevo proyecto de tipo WS

- Seleccionamos nuestro proyecto WEB API Net Core que subimos en Git

- Configuramos de la siguiente manera

- Seleccionamos el plan gratuito

- Creamos una variable de entorno para la cadena de conexión
ConnectionStrings__DefaultConnection
ConnectionStrings__DefaultConnection=Host=XXXX;Port=5432;Database=XXXX;Username=XXXX;Password=XXXX;SSL Mode=Require;Trust Server Certificate=true;

- Hacemos el Deploy de nuestro WS

- Generamos una colección en blanco

- Colocan un nombre

- Añadimos un request

- Colocamos un nombre

- Generamos el URL de la petición, verifiquen que sea GET la petición HTTP

https://controlescolar-api-test.onrender.com/api/estudiantescontrollerapi_test/list_estudiantes?soloActivos=true&tipoFecha=2&fechaInicio=2025-01-01&fechaFin=2025-05-09
Hacemos la petición, obtendremos un error 500
Para observar los errores vayamos a los LOGS de render para identificar el error
- En el Program del API indicaremos nuestra dependencias del proyecto.
using ControlEscolarCore.Controller;
using ControlEscolarCore.Data;
// Configurar la cadena de conexión para PostgreSQLDataAccess
PostgreSQLDataAccess.ConnectionString = builder.Configuration.GetConnectionString("DefaultConnection");
//Agregamos el controller de Estudiantes
builder.Services.AddScoped<EstudiantesController>();
El Program del API queda de la siguiente manera:
using ControlEscolarCore.Controller;
using ControlEscolarCore.Data;
var builder = WebApplication.CreateBuilder(args);
// Configurar la cadena de conexión para PostgreSQLDataAccess
PostgreSQLDataAccess.ConnectionString = builder.Configuration.GetConnectionString("DefaultConnection");
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//Agregamos el controller de Estudiantes
builder.Services.AddScoped<EstudiantesController>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseAuthorization();
app.MapControllers();
app.Run();
- Tenemos que hacer algunas modificaciones en el PostgreSQLDataAccess para que no solo inicie con nuestra cadena de conexión del proyecto Windows Forms, si no que tambien pueda iniciar con la que tenemos en el API
Comentamos la inicialización
// Cadena de conexión desde App.Config
//private static readonly string _ConnectionString = ConfigurationManager.ConnectionStrings["ConexionBD"].ConnectionString;
// Campo estático para almacenar la cadena de conexión
private static string _connectionString;
// Propiedad para establecer la cadena de conexión desde el API
public static string ConnectionString
{
get
{
if (string.IsNullOrEmpty(_connectionString))
{
try
{
// Intenta obtener desde ConfigurationManager (Windows Forms)
_connectionString = ConfigurationManager.ConnectionStrings["ConexionBD"]?.ConnectionString;
}
catch (Exception ex)
{
_logger.Warn(ex, "No se pudo obtener la cadena de conexión desde ConfigurationManager");
}
}
return _connectionString;
}
set { _connectionString = value; }
}
Comentamos el constructor ya que no nos funciona del todo
///// <summary>
///// Constructor privado para implementar el patrón Singleton.
///// </summary>
//private PostgreSQLDataAccess()
//{
// try
// {
// _connection = new NpgsqlConnection(_ConnectionString);
// _logger.Info("Instancia de acceso a datos creada correctamente");
// }
// catch (Exception ex)
// {
// _logger.Fatal(ex, "Error al inicializar el acceso a la base de datos");
// throw;
// }
//}
Nuevo constructor
private PostgreSQLDataAccess()
{
try
{
if (string.IsNullOrEmpty(ConnectionString))
{
throw new InvalidOperationException("La cadena de conexión no está configurada. Asegúrate de establecer PostgreSQLDataAccess.ConnectionString antes de usar la clase.");
}
_connection = new NpgsqlConnection(ConnectionString);
_logger.Info("Instancia de acceso a datos creada correctamente");
}
catch (Exception ex)
{
_logger.Fatal(ex, "Error al inicializar el acceso a la base de datos");
throw;
}
}
-
Generamos versión
-
Subimos versión a GIT
-
Publicamos en Render
-
Probamos de nuevo en POSTMAN