Ověření návrhu ve vrstvě doménového modelu
Tip
Tento obsah je výňatek z eBooku, architektury mikroslužeb .NET pro kontejnerizované aplikace .NET, které jsou k dispozici na .NET Docs nebo jako zdarma ke stažení PDF, které lze číst offline.
V DDD lze ověřovací pravidla považovat za invarianty. Hlavní odpovědností agregace je vynucovat invarianty napříč změnami stavu pro všechny entity v rámci této agregace.
Entity domény by měly být vždy platné entity. Existuje určitý počet invariantů pro objekt, který by měl být vždy pravdivý. Například objekt položky objednávky musí mít vždy množství, které musí být kladné celé číslo plus název a cena článku. Invarianty vynucování je tedy odpovědností entit domény (zejména agregovaného kořenového adresáře) a objekt entity by neměl existovat, aniž by byl platný. Invariantní pravidla jsou jednoduše vyjádřena jako kontrakty a výjimky nebo oznámení jsou vyvolány, když jsou porušeny.
Důvodem je, že k mnoha chybám dochází, protože objekty jsou ve stavu, ve kterých by nikdy neměly být.
Pojďme navrhnout, že nyní máme SendUserCreationEmailService, který přebírá UserProfile ... Jak můžeme v této službě racionalizovat, že název nemá hodnotu null? Zkontrolujeme to znovu? Nebo s větší pravděpodobností ... Jen se nemusíte obtěžovat kontrolovat a "doufat na to nejlepší", doufáme, že někdo obtěžoval ověření, než vám ho poslal. Samozřejmě, použití TDD jeden z prvních testů, které bychom měli napsat, je, že pokud pošlem zákazníkovi s názvem null, že by měl vyvolat chybu. Ale jakmile začneme psát tyto druhy testů znovu a znovu si uvědomujeme ... "co když nikdy nepovolíme, aby jméno bylo null? Neměli bychom všechny tyto testy!".
Implementace ověření ve vrstvě doménového modelu
Ověřování se obvykle implementují v konstruktorech entit domény nebo v metodách, které mohou entitu aktualizovat. Existuje několik způsobů implementace ověření, například ověření dat a vyvolání výjimek v případě selhání ověření. Existují také pokročilejší vzory, jako je použití vzoru specifikace pro ověřování, a vzor oznámení pro vrácení kolekce chyb místo vrácení výjimky pro každé ověření, jak k tomu dochází.
Ověření podmínek a vyvolání výjimek
Následující příklad kódu ukazuje nejjednodušší přístup k ověření v entitě domény vyvoláním výjimky. V tabulce odkazů na konci této části vidíte odkazy na pokročilejší implementace na základě vzorů, které jsme probrali dříve.
public void SetAddress(Address address)
{
_shippingAddress = address?? throw new ArgumentNullException(nameof(address));
}
Lepší příklad by ukázal potřebu zajistit, aby se buď vnitřní stav nezměnil, nebo že došlo ke všem mutacím pro metodu. Například následující implementace ponechá objekt v neplatném stavu:
public void SetAddress(string line1, string line2,
string city, string state, int zip)
{
_shippingAddress.line1 = line1 ?? throw new ...
_shippingAddress.line2 = line2;
_shippingAddress.city = city ?? throw new ...
_shippingAddress.state = (IsValid(state) ? state : throw new …);
}
Pokud je hodnota státu neplatná, první řádek adresy a město již bylo změněno. To může zneplatnit adresu.
Podobný přístup lze použít v konstruktoru entity a zvýšit výjimku, aby byla entita po vytvoření platná.
Použití ověřovacích atributů v modelu na základě datových poznámek
Datové poznámky, jako jsou atributy Required nebo MaxLength, je možné použít ke konfiguraci vlastností pole databáze EF Core, jak je vysvětleno podrobně v části Mapování tabulek, ale už nefungují pro ověřování entit v EF Core (ani IValidatableObject.Validate tato metoda), jak to udělalo od EF 4.x v rozhraní .NET Framework.
Datové poznámky a IValidatableObject rozhraní se stále dají použít k ověření modelu během vazby modelu před obvyklým vyvoláním akcí kontroleru, ale tento model je určený jako Model ViewModel nebo DTO, což se týká MVC nebo rozhraní API, ale nejedná se o problém s doménovým modelem.
Když jste udělali koncepční rozdíl, můžete stále používat datové poznámky a IValidatableObject
ve třídě entity k ověření, pokud vaše akce obdrží parametr objektu třídy entity, který se nedoporučuje. V takovém případě dojde k ověření na vazbě modelu, těsně před vyvoláním akce a můžete zkontrolovat vlastnost ModelState.IsValid kontroleru a zkontrolovat výsledek, ale pak se to stane v kontroleru, ne před uložením objektu entity v DbContext, protože to bylo od EF 4.x.
Stále můžete implementovat vlastní ověřování ve třídě entity pomocí datových poznámek a IValidatableObject.Validate
metody přepsáním Metody SaveChanges DbContext.
Ukázkovou implementaci pro ověřování IValidatableObject
entit v tomto komentáři najdete na GitHubu. Tato ukázka neprovádí ověřování založená na atributech, ale měly by být snadno implementované pomocí reflexe ve stejném přepsání.
Z hlediska DDD je však doménový model nejlépe štíhlý s použitím výjimek v metodách chování vaší entity nebo implementací vzorů specifikace a oznámení k vynucení ověřovacích pravidel.
Může dávat smysl používat datové poznámky v aplikační vrstvě ve třídách ViewModel (místo entit domény), které budou přijímat vstupy, aby bylo možné ověřování modelu v rámci vrstvy uživatelského rozhraní. To by se ale nemělo provádět při vyloučení ověření v rámci doménového modelu.
Ověření entit implementací vzoru specifikace a vzoru oznámení
A konečně složitější přístup k implementaci ověřování v doménovém modelu spočívá v implementaci vzoru specifikace ve spojení se vzorem oznámení, jak je vysvětleno v některých dalších prostředcích uvedených později.
Stojí za zmínku, že můžete také použít jenom jeden z těchto vzorů – například ruční ověřování pomocí řídicích příkazů, ale použití vzoru oznámení k naskládání a vrácení seznamu chyb ověření.
Použití odloženého ověření v doméně
Existují různé přístupy k řešení odložených ověření v doméně. V jeho knize Implementace návrhu řízeného doménou, Vaughn Vernon je popisuje v části o ověření.
Dvoustupňové ověřování
Zvažte také dvoustupňové ověřování. Ověřování na úrovni pole můžete použít pro příkaz Data Transfer Objects (DTOs) a ověřování na úrovni domény uvnitř entit. Můžete to provést vrácením výsledného objektu místo výjimek, aby bylo snazší pracovat s chybami ověření.
Použití ověřování polí s datovými poznámkami, například neduplikujete definici ověření. Provádění ale může být na straně serveru i na straně klienta v případě objektů DTO (například příkazů a modelů ViewModel).
Další materiály
Rachel Appel. Úvod k ověřování modelu v ASP.NET Core MVC
https://learn.microsoft.com/aspnet/core/mvc/models/validationRick Anderson. Přidání ověření
https://learn.microsoft.com/aspnet/core/tutorials/first-mvc-app/validationMartin Fowler. Nahrazení vyvolání výjimek oznámením v ověřeních
https://martinfowler.com/articles/replaceThrowWithNotification.htmlVzory specifikace a oznámení
https://www.codeproject.com/Tips/790758/Specification-and-Notification-PatternsLev Gorodinski. Ověřování v návrhu řízeném doménou (DDD)
http://gorodinski.com/blog/2012/05/19/validation-in-domain-driven-design-ddd/Colin Jack. Ověření doménového modelu
https://colinjack.blogspot.com/2008/03/domain-model-validation.htmlJimmy Bogard. Ověřování ve světě DDD
https://lostechies.com/jimmybogard/2009/02/15/validation-in-a-ddd-world/