En ASP.NET Core 8, el archivo Program.cs juega un papel crucial al dividir su estructura en dos secciones importantes: la configuración de servicios y la activación de servicios. Estas dos partes trabajan juntas para configurar la aplicación y gestionar las solicitudes HTTP de manera eficiente. Al inicio del archivo se realiza la configuración de servicios, donde se define el tipo de aplicación, se añaden bibliotecas de terceros, se configura la autenticación y la autorización, y se registran los servicios para la inyección de dependencias. Esto se realiza mediante el método builder.Services.Add...(). Posteriormente, la activación de los servicios se gestiona justo después de construir la aplicación con builder.Build() y antes de ejecutar la aplicación con app.Run().
El middleware de ASP.NET Core forma parte de la activación de servicios. Se trata de una serie de componentes que procesan las solicitudes HTTP y las respuestas de una manera específica y ordenada. Estos componentes se ensamblan y organizan en un "pipeline" (tubería) en el cual cada uno tiene la oportunidad de actuar sobre la solicitud antes de que esta pase al siguiente componente. Este enfoque modular permite una gran flexibilidad, pues podemos agregar, quitar o reordenar componentes según lo requiera la aplicación.
En este contexto, la inyección de dependencias es esencial para entender cómo funciona la arquitectura de ASP.NET Core. La inyección de dependencias es una técnica que permite desacoplar las clases de servicio, facilitando tanto su mantenimiento como su testabilidad. En lugar de que una clase instancie directamente los servicios mediante un constructor, se le indica qué dependencias necesita. Así, el sistema de inyección de dependencias se encarga de proveer esas dependencias a las clases que las requieren.
ASP.NET Core permite configurar tres tipos de ciclos de vida para los servicios inyectados:
-
Transitorio (Transient): Se crea una nueva instancia del servicio para cada solicitud HTTP. Es útil cuando cada solicitud necesita una instancia separada.
-
Escopado (Scoped): El servicio se instancia una vez por cada solicitud HTTP. Es el ciclo de vida más utilizado, pues garantiza que se crea una instancia única por usuario en una misma solicitud.
-
Singleton: Se instancia una única vez durante toda la vida de la aplicación, compartida por todos los usuarios. Este tipo de servicio debe ser thread-safe, lo cual ASP.NET Core gestiona de manera eficiente.
Es importante destacar que la jerarquía de los ciclos de vida influye en cómo se pueden usar estos servicios entre sí. Un servicio Transitorio puede acceder a servicios Singleton y Scoped, mientras que un servicio Singleton no puede acceder a servicios Scoped o Transitorios, ya que estos tienen un ciclo de vida más corto.
Además de la configuración de servicios, ASP.NET Core permite añadir configuraciones adicionales en archivos como appsettings.json, permitiendo una personalización detallada de la aplicación según el entorno. Por ejemplo, en un entorno de desarrollo, se puede utilizar un archivo appsettings.development.json para sobreescribir configuraciones específicas, como parámetros de un servidor SMTP. El patrón de opciones (Options Pattern) facilita la vinculación de estas configuraciones a clases de C# que luego son inyectadas en los controladores y otros servicios.
El patrón de opciones permite almacenar y recuperar configuraciones de manera estructurada, lo cual mejora la mantenibilidad y escalabilidad de la aplicación. De esta manera, se pueden gestionar configuraciones específicas de la aplicación y del entorno de forma centralizada y reutilizable.
Por último, el uso de la inyección de dependencias permite que las aplicaciones sean más fáciles de probar, pues facilita la creación de mocks o stubs para las dependencias durante las pruebas unitarias. Esta capacidad de desacoplar los servicios de su implementación concreta es uno de los principales beneficios de usar ASP.NET Core y su sistema de inyección de dependencias.
Para los desarrolladores que se inician en ASP.NET Core, es fundamental entender cómo funciona la configuración de servicios, la inyección de dependencias y los ciclos de vida de los servicios. Esto no solo permite escribir código más limpio y organizado, sino que también facilita la implementación de pruebas y la escalabilidad de las aplicaciones. Con esta base, los desarrolladores pueden pasar a explorar otros aspectos de la arquitectura de ASP.NET Core, como la configuración avanzada de middleware, el manejo de solicitudes y las mejores prácticas para trabajar con servicios de larga duración.
¿Qué es HTTP y cómo se implementa correctamente en el desarrollo de APIs con ASP.NET Core?
El Protocolo de Transferencia de Hipertexto (HTTP) es la columna vertebral de la comunicación en la web. Aunque HTTP ha evolucionado con el tiempo, lo más relevante para crear APIs limpias y eficientes con ASP.NET Core es comprender las características esenciales de este protocolo, los métodos de solicitud, los códigos de estado y cómo se gestionan los parámetros entre el cliente y el servidor. A continuación, exploramos estos aspectos con más detalle, dejando de lado aspectos obsoletos o demasiado técnicos.
Características fundamentales de HTTP
El protocolo HTTP se basa en tres principios fundamentales que definen su comportamiento en la red.
Primero, HTTP es sin estado. Esto significa que, después de enviar una solicitud y recibir una respuesta, ni el servidor ni el cliente mantienen información sobre esa interacción. Cada solicitud es independiente y no guarda relación con solicitudes previas.
Segundo, HTTP es sin conexión. La conexión entre el cliente y el servidor se establece para la duración de la solicitud y se cierra una vez que la respuesta ha sido enviada. Esta característica lo hace más ligero y eficiente para la mayoría de los casos de uso en la web. No existe una conexión persistente que mantenga información de estado entre diferentes solicitudes.
Por último, HTTP es independiente de los medios, lo que implica que cualquier tipo de contenido puede ser transmitido siempre que el cliente y el servidor acuerden cómo intercambiarlo, lo que se maneja a través de los encabezados de la solicitud y la respuesta.
Solicitudes y respuestas HTTP
El funcionamiento de una solicitud HTTP es relativamente simple, aunque es necesario entender los detalles para gestionarlas correctamente en el contexto de una API. La solicitud HTTP se inicia cuando un cliente (ya sea un navegador o una aplicación) envía una petición a través de un URI, que especifica el recurso solicitado en el servidor.
Cada solicitud lleva consigo un verbo HTTP, que indica la acción que se desea realizar, como obtener información, enviar datos o modificar un recurso. Además, las solicitudes incluyen encabezados que contienen metadatos como información sobre el tipo de contenido, la autenticación y más. En algunos casos, los parámetros pueden ir en el cuerpo de la solicitud, en la ruta o directamente en el URI.
Cuando el servidor recibe la solicitud, responde con un código de estado que indica cómo se procesó la solicitud. Este código se complementa con encabezados de respuesta, que proporcionan metadatos adicionales, y en algunos casos, con una carga útil (payload) que contiene los datos solicitados, que generalmente estarán formateados en el tipo MIME acordado.
Verbos HTTP
En HTTP existen varios métodos o verbos, definidos principalmente por la RFC 7231. Los más utilizados son:
-
GET: Es el verbo más común y permite obtener un recurso del servidor. Las respuestas a solicitudes GET suelen ser cacheables, lo que significa que el contenido puede ser almacenado en la memoria para futuras solicitudes.
-
POST: Este verbo se utiliza para crear o modificar recursos. A diferencia de GET, el contenido de la solicitud se incluye en el cuerpo (body) de la petición. La respuesta a un POST no suele ser cacheable.
-
PUT: Similar a POST, pero con la diferencia clave de que reemplaza un recurso existente en el servidor. A menudo se confunde con POST debido a su función de modificar datos, pero PUT tiene el comportamiento de reemplazo de recursos, no de adición.
-
DELETE: Como su nombre indica, se utiliza para eliminar un recurso del servidor. La respuesta a DELETE tampoco es cacheable.
-
PATCH: Especificado por la RFC 5789, se utiliza para realizar una modificación parcial de un recurso. A menudo se confunde con PUT y POST, pero su función específica es actualizar parcialmente los recursos en el servidor.
Códigos de estado HTTP
Los códigos de estado HTTP proporcionan una forma de comunicar el resultado de la solicitud realizada. Los más comunes incluyen:
-
200 OK: La solicitud se procesó correctamente y la respuesta contiene los datos solicitados.
-
201 Created: Indica que un recurso ha sido creado como resultado de una solicitud POST.
-
400 Bad Request: La solicitud es incorrecta o está mal formada.
-
401 Unauthorized: La solicitud requiere autenticación.
-
404 Not Found: El recurso solicitado no se encuentra disponible.
-
500 Internal Server Error: El servidor encontró un error inesperado al procesar la solicitud.
Códigos y encabezados de respuesta
Cuando un servidor responde a una solicitud, no solo devuelve un código de estado, sino que también incluye encabezados de respuesta. Estos encabezados pueden contener información útil como el tipo de contenido, la longitud del contenido o detalles sobre cómo manejar el almacenamiento en caché del contenido.
En algunos casos, la respuesta también incluye una carga útil que puede ser en formato JSON, XML o cualquier otro formato que el cliente haya solicitado. Esto es particularmente importante cuando se trabaja con APIs RESTful, donde la carga útil contiene los datos necesarios para la interacción con el servicio.
Técnicas avanzadas para la gestión de solicitudes HTTP
Aunque el enfoque de este texto se centra en los aspectos básicos de HTTP, es fundamental conocer y aplicar técnicas más avanzadas para optimizar el rendimiento y la seguridad de las aplicaciones. Algunas de estas técnicas incluyen el manejo adecuado de cookies, la implementación de autenticación y autorización a través de encabezados HTTP, y el uso de CORS (Cross-Origin Resource Sharing) para gestionar las restricciones de seguridad en aplicaciones web.
Por ejemplo, aunque en este libro no profundizamos en los detalles de las cookies, es importante saber que, en aplicaciones web, estas se utilizan para almacenar información en el cliente, lo que permite mantener el estado entre diferentes solicitudes. Esto es fundamental para la gestión de sesiones de usuario. Si bien en este libro nos centramos en métodos más modernos, como los tokens JWT, entender las cookies y su funcionamiento es crucial para desarrollar APIs que interactúan con navegadores de manera eficiente.
La seguridad en las aplicaciones web también debe ser considerada. HTTP por sí mismo no proporciona cifrado, por lo que es crucial utilizar HTTPS (HTTP sobre SSL/TLS) para asegurar las conexiones y proteger los datos transmitidos entre el cliente y el servidor. Aunque el protocolo HTTP 2 y 3 mejoran la eficiencia y el rendimiento de la comunicación, siempre es importante tener en cuenta que la seguridad debe ser una prioridad en la construcción de cualquier aplicación moderna.

Deutsch
Francais
Nederlands
Svenska
Norsk
Dansk
Suomi
Espanol
Italiano
Portugues
Magyar
Polski
Cestina
Русский