Validace vlastností objektu

Tomáš Holan       16. 11. 2011             5784 zobrazení

Assembly System.ComponentModel.DataAnnotations.dll , která je standardně součástí .NET Frameworku, obsahuje atributy určené pro deklaraci validačních podmínek členských prvků (vlastností) objektů na úrovni business logiky nebo např. na úrovni datového entity modelu. Tyto atributy jsou pak využitelné ve spojení s nějakou další technologií nebo infrastrukturou (*) například pro provádění validace uživatelských vstupů formuláře aplikace. V tomto příspěvku si ale ukážeme jak je možné stejná metadata využít pro libovolný objekt a jak provádět jeho validaci přímo bez návaznosti na jinou technologii.

Budete mít tedy definovaný nějaký objekt, jehož vlastnosti mohou odpovídat například konfiguraci nebo parametrům implementovaného logického procesu. Před spuštěním daného procesu budeme ale chtít provést validaci, že je konfigurace správná nebo parametry správně nastaveny. Pro deklaraci vlastních validačních podmínek s výhodou použijeme právě data annotations a proto bude třeba dořešit, jak spustit obecnou validaci, která metadata použije. Ještě radši upozorním na důležitý fakt, že veškeré kontroly se budou spouštět pro již existující instanci objektu tj. z hlediska existence objektu se připouští validní i nevalidní instance. To je rozdíl oproti případu, kdy by se validace prováděli už při vytváření objektu samotného v konstruktoru (**).

Jako příklad můžeme použít scénář z předchozího článku. Například definice třídy ImportCsv doplněná o validační podmínky by pak mohla vypadat takto:

using System;
using System.ComponentModel.DataAnnotations;

public class ImportCsv : Import
{
    #region member varible and default property initialization
    [Required]
    public string InputFilename { get; set; }
    [Required]
    public string WorkingFolder { get; set; }
    [Required]
    public string ArchiveFolder { get; set; }
    public bool IgnoreFirstRow { get; set; }
    #endregion

    #region action methods
    public override void Initialize()
    {
        //Zde již chceme mít objekt ověřen
        //Inicializace filewatcheru
        Console.WriteLine("ImportCsv: InputFilename=\"{0}\", WorkingFolder=\"{1}\", ArchiveFolder=\"{2}\", IgnoreFirstRow={3}", this.InputFilename, this.WorkingFolder, this.ArchiveFolder, this.IgnoreFirstRow);
    }

    public override void Dispose(bool disposing)
    {
        //Uvolnění objektu
    }
    #endregion
}

Zde budeme tedy chtít pouze kontrolovat, že jsou nastaveny povinné parametry InputFilename, WorkingFolder a ArchiveFolder, ale obecně nám nic nebrání použít i podmínky další. Kontrola by se měla provést před voláním metody Initialize. Obdobně je možné změnit i třídy Backup a ImportDb.

A jak tedy spustit validaci všech členů objektu? Pro tento účel existuje v již zmiňované assembly DataAnnotations třída Validator. Pozor ale, že tato třída byla doplněna až od .NET Frameworku verze 4.0 tj. starší verze této assembly tuto podporu v sobě nemá.

Základní použití třídy Validator vypadá následovně:

Validator.ValidateObject(obj, new ValidationContext(obj, null, null), true);

Uvedené volání provede validaci všech “odekorovaných” vlastností objektu obj. Pozor, že reference na objekt je zde předávána dvakrát. Při volání jsou nejprve kontrolovány všechny atributy RequiredAttribute a až poté všechny ostatní atributy. Volání vyhodí ValidationException odpovídající první validační chybě (pokud nastala). Výchozí text výjimky lze případně změnit jeho uvedením přímo v daném atributu a to buď přímo nebo odkazem na resource.

Pro rozšíření naší infrastruktury z minula doplníme toto volání v konstruktoru třídy ModuleManager před volání inicializaci jednotlivých modulů:

var module = (IModule)System.Windows.Markup.XamlReader.Parse(el.ToString());

//Validace konfigurace modulu
Validator.ValidateObject(module, new ValidationContext(module, null, null), true);

module.Initialize();

A ještě alespoň stručně, jaké atributy resp. podmínky lze tímto způsobem na objektech validovat. Všechny validační atributy dědí ze základní třídy ValidationAttribute a přímo definují logiku pro validaci dané hodnoty. Patří mezi ně hlavně tyto:


(*) Příkladem může být například ASP.NET Dynamic Data, ASP.NET MVC, WCF RIA Servicesa další technologie nebo validační frameworky.

(**) Obecně je první způsob nevýhodný v tom, že možný nevalidní stav instance musíme v celé implementaci objektu obsloužit a také, že objekt nemůže být immutable. Druhý způsob je zase nevýhodný v tom, že musíme veškeré nastavení předávat již do volání konstruktoru (což může vést na větší počet přetížení konstruktoru a tím na nepřehledné API). Jedním ze způsobů, jak lze nevýhody obou těchto přístupů řešit, je použít oba současně tj. zavést pomocnou builder třídu (ta použije první způsob) pro konstrukci třídy druhé - finálního objektu (ta použije způsob druhý).

 

hodnocení článku

0 bodů / 1 hlasů       Hodnotit mohou jen registrované uživatelé.

 

Nový příspěvek

 

RE: Validace vlastností objektu

Ahoj Jirko,

Co se týče reflexce, ano ta se uvnitř validatoru používá, konkrétně pro načtení vlastností s atributy a zjištění jejich aktuálních hodnot. Pro to načítání vlastností je tam ale nějaký mechanizmus pro cachování, takže se tak děje jen 1x pro daný datový typ.

Vyhození jedné exception bych se v tomto případě asi nebál a použít při porušení validačních pravidel jako signalizaci tohoto stavu vyjímku my příjde asi také v pořádku. Pokud by to ale v nějakém scénaři vadilo, nabízí třída Validator i metodu TryValidateObject, která dle očekávání exception nevyhazuje, ale vrací bool hodnotu.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

RE: Validace vlastností objektu

Zajímalo by mě, jak je taková validace výkonná? Protože z použití atributů, které se pak kontrolují, je patrné, že se používá reflexe, která není nejvýkonnější. Dále přibyl validátor, který vyhazuje výjimku, aby dal najevo, že není se stavem objektu spokojen. Je zajímavé, že MS se vydává u některých technologií tímto směrem, přitom se obecně doporučuje reflexi a práci s metdaty nepoužívat za tímto účelem a stejně tak je tomu s řízením kódu výjimkami, které je obecně považováno za Bad practice.

Jirka

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback