Walidacja domeny

Odpowiedz Nowy wątek
2020-08-12 01:11

Rejestracja: 6 lat temu

Ostatnio: 55 minut temu

Lokalizacja: Nowa Ruda

0

Witam. Robię sobie wieczorami projekt api. Mam tam sobie handlery commands itp. No i jest warstwa domeny (moje encje). Powiedzmy, że chce jak to tylko możliwe, kontrolować tworzenie obiektów domeny (Są konstruktory, prywatne sety itp). Nie chce dopuscić do utworzenia obiektu który będzie miał np puste pole Name.
Jakie jest wasze podejście w tej kwestii?
1 .No można w każdym type (np w konstruktorze ) dawać ify typu string is null or empty i rzucać wyjątek.

  1. Można jakieś klasy osobne walidujące obiekt (każdy typ ma swój walidator)
  2. Ja ostatnio w ramach małego treningu stwierdziłem, że może zrobię to na atrubutach. coś w tym stylu. https://www.codeproject.com/A[...]ion-Engine-for-Domain-Objects . Czyli tworzę obiekt np metodą statyczną zwracającą dany typ i przed zwróceniem obiektu waliduje go tymi powiedzmy ValidationEngine.
internal abstract class BaseValidationEngine<TAttribute, TValue> 
        where TAttribute : Attribute, IValidationAttribute<TValue>

    {
        protected List<ValidationError> errors { get; }
        public BaseValidationEngine()
        {
            errors = new List<ValidationError>();
        }
        protected void Validate<T>(T item)
        {
            var properties = item.GetType().GetProperties(
                BindingFlags.Public | BindingFlags.Instance);

            foreach (var property in properties)
            {
                var validationAttributes = property.GetCustomAttributes(typeof(TAttribute),
                    true);

                foreach (var att in validationAttributes)
                {
                    var valAtt = att as TAttribute;

                    if (valAtt is null) continue;

                    if (!valAtt.IsValid((TValue)property.GetValue(item, null)))
                    {
                        errors.Add(new ValidationError
                        {
                            Field = property.Name,
                            Message = valAtt.Message
                        });
                    }
                }

            }
        }
    }

a konkretny walidator wygląda np tak:

internal class NotNullOrEmptyValidationEngine
        : BaseValidationEngine<NotNullOrEmptyAttribute, string>, IValidationEngine
    {

        public List<ValidationError> ValidateEntity<T>(T item)
        {
            base.Validate(item);
            return base.errors;
        }
    }

A wszystkie walidatory uruchamiam tak:

public static void Validate<T>(T entity) where T : class
        {
            List<ValidationError> errors = new List<ValidationError>();
            var engines = ValidatorsFactory.GetValidationEngines();
            foreach (var engine in engines)
            {
                var result = engine.ValidateEntity(entity);
                errors.AddRange(result);
            }

            if (errors.Any())
                throw new DomainValidationException(errors, $"Cannot create {nameof(T)}");
        }

Z zalet tego rozwiązania to dla mnie: nie powtarzam kodu (po raz n-ty string.IsNull...), dołożenie nowej walidacji nie wymaga zmian w istniejącym kodzie.
Z minusów: to chyba overenginering :P, refleksja?

  1. Co innego można zastosować

Pozostało 580 znaków

2020-08-12 02:14
Moderator

Rejestracja: 12 lat temu

Ostatnio: 17 godzin temu

Lokalizacja: Wrocław

2

Jeśli chodzi o encje, to w konstruktorach, bo nigdy nie chcę mieć ich w niepoprawnym stanie.

Takie walidatory są dobre do obiektów wejściowych: jakich viewmodeli czy DTO, bo te z definicji mogą mieć niepoprawne wartości. Tylko nie ma sensu pisać tego samodzielnie, od tego jest FluentValidation..


"HUMAN BEINGS MAKE LIFE SO INTERESTING. DO YOU KNOW, THAT IN A UNIVERSE SO FULL OF WONDERS, THEY HAVE MANAGED TO INVENT BOREDOM."

Pozostało 580 znaków

2020-08-12 08:23

Rejestracja: 6 lat temu

Ostatnio: 55 minut temu

Lokalizacja: Nowa Ruda

0
somekind napisał(a):

Jeśli chodzi o encje, to w konstruktorach, bo nigdy nie chcę mieć ich w niepoprawnym stanie.

Takie walidatory są dobre do obiektów wejściowych: jakich viewmodeli czy DTO, bo te z definicji mogą mieć niepoprawne wartości. Tylko nie ma sensu pisać tego samodzielnie, od tego jest FluentValidation..

No Fluenta jak najbardziej używam do tych rzeczy. Mialem na myśli samą domenę. Mam tych pół trochę w danej encji. W konstruktorze to jedno miejsce. Ale potem jest jakiś update. I to samo trzeba robić i tak we wszystkich encjach

Pozostało 580 znaków

2020-08-12 09:04

Rejestracja: 9 lat temu

Ostatnio: 1 minuta temu

4

Ale jeśli encje zmieniasz tylko przez metody, które w nich są to nie powinno się dać ustawić niepoprawnego stanu. Więc zamiast walidacji poprawności to metody do zmiany stanu powinny zapewniać, że ten stan będzie zawsze poprawny.


Pozostało 580 znaków

2020-08-12 17:50

Rejestracja: 6 lat temu

Ostatnio: 54 minuty temu

Lokalizacja: Gdańsk

2
mar-ek1 napisał(a):

Ale jeśli encje zmieniasz tylko przez metody, które w nich są to nie powinno się dać ustawić niepoprawnego stanu. Więc zamiast walidacji poprawności to metody do zmiany stanu powinny zapewniać, że ten stan będzie zawsze poprawny.

Dokładnie, to domena (encja w Twoim przypadku) powinna sama dbać o to, żeby nie znaleźć się nigdy w niepoprawnym stanie.


Pozostało 580 znaków

Odpowiedz

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0