Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
April 8, 2022 12:52 am GMT

[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.

Solucin original

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:
Solucin refactorizada

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

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To