ASP.NET Vertical Slice Architecture Sablon
- Tulajdonos
- maidics
- Létrehozva
- 2026. máj. 16.
- Utolsó push
- 2026. okt. 13.
Könnyed vertical slice sablon ASP.NET Core-hoz. Kizárólag web API, Aspire-rel összehangolva. Unit, funkcionális és web tesztelés TUnit keretrendszerrel. Elérhető GitHub-on és NuGet-en.
Ez a dokumentum azt bemutatja, hogy milyen kihívásokkal találkoztam a téma feldolgozása során, és hogyan oldottam meg őket.
A MediatR kiváltása
Ezzel a sablonnal egy könnyűsúlyú kiindulópontot szerettem volna adni az ASP.NET Core-os fejlesztéshez.
A vertical slicing egyszerűbb és gyorsabb munkát tesz lehetővé, mint a Clean Architecture, ugyanakkor a sablon kialakításához sok ötletet merítettem Jason Taylor Clean Architecture sablonjából.
Emellett a lehető legkevesebb NuGet-csomagra akartam támaszkodni, így a MediatR-ről is le kellett mondanom.
Az IRequest és IRequestHandler absztrakciók kiváltása meglepően egyszerűnek bizonyult:
- az interfészeket magam írtam meg,
- induláskor reflection segítségével regisztrálom őket a DI-ba,
- közvetlenül injektálhatók a Minimal API endpointokba.
Ezzel viszont elveszítjük azt, ami szerintem a MediatR legértékesebb része: az IPipelineBehavior-t. Sok sablon erre építi például a következőket:
- logolás (pl.
IRequest-enként, illetve teljesítményproblémák vagy kezeletlenExceptionesetén), - validáció,
- sőt, akár a jogosultságkezelés is...
Az ASP.NET Core-ban viszont eleve van egy bővíthető pipeline: a HTTP-kérések feldolgozási pipeline-ja. Ezt middleware-rel vagy IEndpointFilter-ekkel lehet kiegészíteni.
A naplózást, a validációt és a teljesítményfigyelést ez utóbbival oldottam meg:
LoggingFilter: egyszerű filter, amely naplózza a beérkező HTTP-kéréseket; fejlesztéshez implementálva,PerformanceFilter: naplózza azokat a kéréseket, amelyek 500 ms-nál tovább futnak,ValidationFilter:- a DI-ból lekéri az összes olyan
IValidatorszolgáltatást (FluentValidation), amely az endpoint metódus paramétereként kapottIRequest-hez van regisztrálva, - ebből következik, hogy az automatikus validációhoz magának az
IRequestobjektumnak kell az endpoint paraméterének lennie, - az
IPipelineBehavior-alapú megoldáshoz képest ez hamarabb jelez hibát: a validáció még az endpoint metódus meghívása előtt lefut.
- a DI-ból lekéri az összes olyan
A korábbi verziókban saját domain event implementáció is volt, de több okból kivettem:
- egymásba ágyazott mentésekhez vezetett az adatbázis-kontextusban,
- erre a célra léteznek NuGet-csomagok, amelyek jobb megoldásokat kínálnak.
A tesztek felépítése
A tesztek szervezésénél volt néhány kifejezetten junior pillanatom, így a struktúra verzióról verzióra sokat változott:
- v2.1.0: tesztek a sablonnal együtt szállított kódhoz, például az
AuditableEntityInterceptor-hoz vagy aProblemDetailsExceptionHandler-hez, - v2.3.0: a sablon tesztjeit külön projektbe tettem, mert más tesztinfrastruktúrát igényeltek,
- v2.6.0: külön unit teszt projekt azoknak a teszteknek, amelyekhez nem kell különösebb előkészítés (app host, adatbázis stb.),
- v3.0.0:
- NUnit helyett a TUnit tesztkeretrendszerre váltottam,
- a TUnit-nak köszönhetően minden tesztet egy projektbe vonhattam össze (a sablon tesztjei továbbra is külön maradtak),
- bekerültek az E2E tesztek, amelyek
HttpClient-en keresztül küldenek HTTP-kéréseket, - sőt, még a sablon tesztprojektjét is átszerveztem...
A v3.0.0-val az volt a célom, hogy a tesztprojekt is vertical slice struktúrát kövessen, és mindent egyetlen, a fő projekt szerkezetét követő .csproj alá tegyek.
Ez nehézkesnek és kuszának bizonyult, mert a különböző tesztek eltérő infrastruktúrát és függőségeket igényelnek.
A v4.0.0-val úgy érzem, megtaláltam a tesztstruktúra végleges formáját:
-
UnitTests:- unit és funkcionális tesztek,
- mockolt szolgáltatások, szerver nélkül, memóriában futó alkalmazás, Aspire által menedzselt adatbázissal (a
TestAppHost-ból), - egyszerű osztályok, extension metódusok és
IRequestHandlerimplementációk tesztelésére.
-
IntegrationTests:- a solution infrastruktúráját célozza, vagyis a külső függőségekkel rendelkező kódot,
- a sablon ehhez egy üres projektet biztosít,
- nem hivatkozik a TUnit-ra, hogy a
dotnet testne lépjen ki 8-as kóddal (egyetlen teszt sem futott le).
-
WebTests:- E2E tesztek (endpointokon keresztül),
- memóriában futó alkalmazás Kestrellel, az adatbázist az Aspire biztosítja.
Ez a felállás tisztán elkülönítve lefed mindent, amit a sablon kínál.