An Interest In:
Web News this Week
- April 27, 2024
- April 26, 2024
- April 25, 2024
- April 24, 2024
- April 23, 2024
- April 22, 2024
- April 21, 2024
[Parte 6] ASP.NET: Refactorizando la solucin (Vertical Slice Architecture)
Introduccin
Este artculo realmente no veremos nada nuevo, pero necesito hacerlo porque vamos a seguir explorando conceptos y trucos en ASP.NET. Al inicio no quera complicarlo dividiendo todo por proyectos y capas. Pero si lo hacemos con Vertical Slice Architecture, ser muy sencillo y bien estructurado.
Ya he escrito sobre este tema, tengo un repositorio, un vdeo y este artculo donde exploramos ms sobre Vertical Slice Architecture.
Te recomiendo que visites ese contenido si quieres leer ms sobre este tema.
Nota: Como siempre, aqu te dejo el cdigo que corresponde a este post.
Siempre puedes buscarme en mi twitter.
Refactorizando la Solucin
Esta series de post naci de una sola idea, que era implementar CQRS y validaciones con FluentValidation (por eso la solucin se llama MediatRValidationExample ) y pues una cosa llev a otra y ya tengo planeado 10 o ms partes.
As est ahorita la solucin, un proyecto Web que contiene todo el cdigo. Est dividido por technical concerns eso s, pero vamos uno por uno que es cada cosa para que nos sirva de repaso:
Presentacin
La presentacin o UI, en trminos prcticos es todo aquello relacionado con la Web API. Aqu el resumen de lo que tenemos perteneciente a este layer:
- Controllers: Los controllers forman parte de la UI y esta carpeta la dejaremos intacta donde est.
- Filters: Los filtros se aplican a los controllers, por lo tanto es algo totalmente acoplado a la presentacin
- Services (parcialmente): En Services contamos con la implementacin de
CurrentUserService
. Esta clase est acoplada al HttpContext, pero cuenta con una interfaz para crear la abstraccin necesaria.- Nota: Siempre es bueno abstraer cuando es necesario, no simplemente crear abstracciones "por que s"
Application Core
En Vertical Slice Architecture aqu encontraremos el resto de la aplicacin, si lo comparamos con Clean Architecture, aqu tendremos tanto Domain, Core, Persistence e Infraestructura
Por qu juntos? ese es otro tema, te recomiendo que visites el contenido mencionado anteriormente.
En fin, para el core actualmente tenemos:
- Behaviours: Los decoradores agregados utilizando MediatR, estos agregan reglas de negocio u otras funcionalidades propias de las reglas de la aplicacin.
- Exceptions: Excepciones custom que al igual que los behaviours, agregan lgica/reglas al core.
- Helpers (aka Utils): Este es medio random que se agreg en el post de Hash Ids, pero si solo se usan en core, pues se quedan en core.
- Domain: Todo lo relacionado al dominio (value objects, entities, enums, entity exceptions, domain services, etc)
- Features: Todos los slices de la aplicacin
- Infrastructure: Adapters / Services para servicios externos
- Persistence: La base de datos (EF Core)
Por lo que la solucin, una vez refactorizada, quedara as:
Si estas siguiendo estos tutoriales, te recomiendo que no hagas el refactor, es mejor que descargues el cdigo y lo analices, pero trato de explicar el por qu la parte 7 de esta serie de posts, ser un poco ms diferente .
Update de Dependency Injection
Ahora dejamos que cada proyecto registre sus dependencias (Web y Core) y agregu dos clases con extensiones para hacerlo. La clase DependencyInjection
.
ApplicationCore -> DependencyInjection
using FluentValidation;using MediatR;using MediatrExample.ApplicationCore.Common.Behaviours;using MediatrExample.ApplicationCore.Infrastructure.Persistence;using Microsoft.AspNetCore.Authentication.JwtBearer;using Microsoft.AspNetCore.Identity;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;using Microsoft.IdentityModel.Tokens;using System.Reflection;using System.Text;namespace MediatrExample.ApplicationCore;public static class DependencyInjection{ public static IServiceCollection AddApplicationCore(this IServiceCollection services) { services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly()); services.AddMediatR(Assembly.GetExecutingAssembly()); services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehaviour<,>)); services.AddAutoMapper(Assembly.GetExecutingAssembly()); return services; } public static IServiceCollection AddPersistence(this IServiceCollection services, string connectionString) { services.AddSqlite<MyAppDbContext>(connectionString); return services; } public static IServiceCollection AddSecurity(this IServiceCollection services, IConfiguration config) { services .AddIdentityCore<IdentityUser>() .AddRoles<IdentityRole>() .AddEntityFrameworkStores<MyAppDbContext>(); services .AddHttpContextAccessor() .AddAuthorization() .AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = config["Jwt:Issuer"], ValidAudience = config["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config["Jwt:Key"])) }; }); return services; }}
Realmente aqu pude ponerlo todo dentro del mismo mtodo AddApplicationCore
, pero quise hacer distinciones y segmentarlo segn su propsito.
Nota : Todo esto es una referencia, puedes tomar lo bueno y lo que consideres malo, dejarlo. El tema Vertical Slice es muy interesante, busca ms sobre el tema y Jimmy Boggard.
WebApi -> DependencyInjection
using FluentValidation.AspNetCore;using MediatrExample.ApplicationCore.Common.Interfaces;using MediatrExample.WebApi.Filters;using MediatrExample.WebApi.Services;using Microsoft.AspNetCore.Mvc;using Microsoft.OpenApi.Models;namespace MediatrExample.WebApi;public static class DependencyInjection{ public static IServiceCollection AddWebApi(this IServiceCollection services) { services.AddEndpointsApiExplorer(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" }); c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { In = ParameterLocation.Header, Description = "Please insert JWT with Bearer into field", Name = "Authorization", Type = SecuritySchemeType.ApiKey }); c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] { } } }); }); services.AddControllers(options => options.Filters.Add<ApiExceptionFilterAttribute>()) .AddFluentValidation(); services.Configure<ApiBehaviorOptions>(options => options.SuppressModelStateInvalidFilter = true); services.AddScoped<ICurrentUserService, CurrentUserService>(); return services; }}
Es exactamente lo mismo, pero antes todo se encontraba en el Program
y siempre se empieza a ver feo. Siempre recomendar separarlo con extensiones para hacerlo ms legible y ms fcil de entender cuando miras el Program
.
WebApi -> Program
using MediatrExample.ApplicationCore;using MediatrExample.ApplicationCore.Domain;using MediatrExample.ApplicationCore.Infrastructure.Persistence;using MediatrExample.WebApi;using Microsoft.AspNetCore.Identity;var builder = WebApplication.CreateBuilder(args);builder.Services.AddWebApi();builder.Services.AddApplicationCore();builder.Services.AddPersistence(builder.Configuration.GetConnectionString("Default"));builder.Services.AddSecurity(builder.Configuration);var app = builder.Build();// Configure the HTTP request pipeline.if (app.Environment.IsDevelopment()){ app.UseSwagger(); app.UseSwaggerUI();}app.UseHttpsRedirection();app.UseAuthentication();app.UseAuthorization();app.MapControllers();await SeedProducts();app.Run();// Seed omitido...
Program
ahora se ve ms limpio, cualquier cosa que quieras ver como est configurado, simplemente te metes al mtodo de extensin correspondiente y ya.
Conclusin
Realmente no hay mucho que concluir, solo quise explicar el refactor para los prximos posts y pues realmente al inicio no queria complicarlo, quera hacerlo simple.
Siempre manej las carpetas correspondientes, por lo que este refactor no debe de presentar problema alguno.
Original Link: https://dev.to/isaacojeda/parte-6-aspnet-refactorizando-la-solucion-vertical-slice-architecture-d39
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To