$mermaidjs
Clean Architecture Demo
Loading...
Searching...
No Matches
Program.cs
Go to the documentation of this file.
1// Este archivo es la raíz de composición y configuración de inicio de la aplicación.
2//
3// Rol en Clean Architecture:
4// - Parte de la capa de presentación, en este caso, API REST
5// - Raíz de Composición: Conecta todas las dependencias a través de Inyección de Dependencias
6// - Configuración: Configura pipeline de middleware, autenticación y servicios
7// - Punto de entrada: ASP.NET Core ejecuta este archivo en el inicio de la aplicación
8//
9// Responsabilidades:
10// - Registrar servicios de todas las capas en el contenedor de DI
11// - Configurar autenticación y autorización
12// - Agregar servicios de acceso a datos y persistencia
13// - Configurar pipeline de middleware (¡el orden importa!)
14// - Inicializar base de datos si es necesario
15//
16// Patrón de Inyección de Dependencias:
17// - Registra interfaces de capas de Aplicación y Dominio
18// - Implementaciones de capa de Infraestructura
19// - Los controladores usan servicios registrados (inyección de constructor)
20// - Los manejadores de MediatR usan servicios registrados
21//
22// Registro de Capa de Arquitectura:
23// - Capa del dominio: IUnitOfWork
24// - Capa de Aplicación: ITaskRepository, IDomainEventDispatcher, MediatR, FluentValidation, ValidationBehavior
25// - Capa de Infraestructura: DbContext, Repositorios, Distribuidor de Eventos
26// - Capa de UI: Controladores, Middleware
27//
28// Directrices de Raíz de Composición:
29// - La capa de UI puede hacer referencia a Infraestructura para registro de DI
30// - Infraestructura implementa interfaces de otras capas
31// - Las capas del dominio y Aplicación permanecen independientes
32// - Este archivo es el único lugar donde se hace referencia directa a Infraestructura
33//
34// pipeline de Middleware:
35// - El orden es crítico: el middleware anterior procesa solicitudes primero
36// - ExceptionHandlingMiddleware: Usualmente primero para capturar todas las excepciones
37// - Autenticación, Autorización: Middleware relacionado con seguridad
38// - MapControllers: Enruta solicitudes a controladores
39
40using System.Reflection;
41using System.Text.Json.Serialization;
42using FluentValidation;
43using MediatR;
44using Microsoft.AspNetCore.Authentication.JwtBearer;
45using Microsoft.Data.Sqlite;
46using Microsoft.EntityFrameworkCore;
47using Microsoft.IdentityModel.Tokens;
54
55var builder = WebApplication.CreateBuilder(args);
56
57// Cargar secretos de usuario explícitamente para que los tokens dotnet user-jwts funcionen incluso cuando
58// el proceso se inicia sin ASPNETCORE_ENVIRONMENT=Development.
59builder.Configuration.AddUserSecrets(Assembly.GetExecutingAssembly(), optional: true);
60
61const string connectionString = "Data Source=file:taskmanagement?mode=memory&cache=shared";
62builder.Configuration.AddInMemoryCollection(new Dictionary<string, string?> {
63 ["ConnectionStrings:DefaultConnection"] = connectionString
64});
65
66builder.Services.AddSingleton<SqliteConnection>(_ => {
67 var connection = new SqliteConnection(connectionString);
68 connection.Open();
69 return connection;
70});
71
72var bearerSection = builder.Configuration.GetSection("Authentication:Schemes:Bearer");
73var validIssuer = bearerSection["ValidIssuer"];
75 .GetSection("ValidAudiences")
76 .Get<string[]>() ?? [];
78 .GetSection("SigningKeys")
79 .GetChildren()
80 .Select(x => x["Value"])
81 .Where(x => !string.IsNullOrWhiteSpace(x))
82 .Select(x => new SymmetricSecurityKey(Convert.FromBase64String(x!)))
83 .Cast<SecurityKey>()
84 .ToArray();
85
86builder.Services
87 .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
88 .AddJwtBearer(options => {
89 options.TokenValidationParameters = new TokenValidationParameters {
90 ValidateIssuer = !string.IsNullOrWhiteSpace(validIssuer),
91 ValidIssuer = validIssuer,
92 ValidateAudience = validAudiences.Length > 0,
93 ValidAudiences = validAudiences,
94 ValidateIssuerSigningKey = true,
95 IssuerSigningKeys = signingKeys,
96 ValidateLifetime = true,
97 TryAllIssuerSigningKeys = true,
98 ClockSkew = TimeSpan.FromMinutes(1)
99 };
100 });
101builder.Services.AddAuthorization();
102
103// Agregar servicios al contenedor
104builder.Services
105 .AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(TaskManagement.Application.Commands.CreateTaskCommand).Assembly))
106 .AddValidatorsFromAssembly(typeof(TaskManagement.Application.Commands.CreateTaskCommand).Assembly)
108 .AddDbContext<TaskDbContext>(options =>
109 options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection")))
110 .AddScoped<IUnitOfWork>(sp => sp.GetRequiredService<TaskDbContext>())
111 .AddScoped<ITaskRepository, TaskRepository>()
113 .AddScoped<IDomainEventDispatcher, MediatRDomainEventDispatcher>()
114 .AddControllers()
115 .AddJsonOptions(options => {
116 options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
117 });
118var app = builder.Build();
119
120using (var scope = app.Services.CreateScope())
121{
122 var dbContext = scope.ServiceProvider.GetRequiredService<TaskDbContext>();
123 dbContext.Database.EnsureCreated();
124}
125
126// Configurar pipeline de middleware
128
129app.UseHttpsRedirection();
130app.UseAuthentication();
131app.UseAuthorization();
132app.MapControllers();
133
134app.Run();
135
140public partial class Program
141{
142 // Intencionalmente en blanco.
143}
var validIssuer
Definition Program.cs:73
var validAudiences
Definition Program.cs:74
var builder
Definition Program.cs:55
var app
Definition Program.cs:118
app.Services.CreateScope()) { var dbContext=scope.ServiceProvider.GetRequiredService< TaskDbContext >() scope
Definition Program.cs:122
builder.Services. typeof(ValidationBehavior<,>)) .AddDbContext< TaskDbContext >(options
const string connectionString
Definition Program.cs:61
var signingKeys
Definition Program.cs:77
var bearerSection
Definition Program.cs:72
Partial Program class made public for testing purposes. Allows WebApplicationFactory to access the Pr...
Definition Program.cs:141
ExceptionHandlingMiddleware es middleware de ASP.NET Core para manejo centralizado de excepciones.
ValidationBehavior es un comportamiento de pipeline de MediatR para validar comandos y consultas.
CreateTaskCommand encapsula la solicitud de creación de una nueva tarea.
TaskReadRepository es el repositorio de lectura para consultas de tarea optimizadas.
TaskDbContext es el DbContext de Entity Framework Core para gestión de tareas.
ITaskReadRepository es la abstracción para consultas de sólo lectura de tareas.