Wstrzykiwanie zależności do ViewModel podczas bindowania modelu

Odpowiedz Nowy wątek
2018-11-25 13:51
0

Czy da się poprzez konstruktor wstrzyknąć obiekt MyEfContext do klasy AddStudentViewModel podczas bindowania modelu? Jeśli nie, to w jaki sposób najlepiej otrzymać kontekst bazy danych w metodzie IsValid()?

Controller

public class StudentController : Controller
{
    [HttpPost]
    public IActionResult Add(AddStudentViewModel vm)
    {
        if (!ModelState.IsValid || !vm.IsValid())
        {
            return View();
        }

        //add student
        return RedirectToAction("Index");
    }
}

ViewModel

public class AddStudentViewModel
{
    private MyEfContext _context;

    public AddStudentViewModel() 
    {
    }

    public AddStudentViewModel(MyEfContext context) 
    {
        _context = context;
    }

    public string UniqueName { get; set; }
    public int Age{ get; set; }

    public bool IsValid()
    {
        if (_context.Students.Any(x => x.UniqueName == UniqueName))
        {
              return false;
        }

        return true;
    }
}

Pozostało 580 znaków

2018-11-25 14:12

Nie, dostaniesz InvalidOperationException, bo bindowany ViewModel musi mieć konstruktor bezparametrowy.

Żeby zrobić ręczną walidację, czy spełnione są customowe warunki wykorzystaj własny atrybut ValidationAttribute: https://docs.microsoft.com/pl[...]netcore-2.1#custom-validation

Pozostało 580 znaków

2018-11-25 17:08
var
4

Podpięcie czegokolwiek powiązanego z bazą danych do viewmodelu to jedna z najgorszych rzeczy jaką możesz zrobić

Pozostało 580 znaków

2018-11-25 19:28
0

Podpięcie czegokolwiek powiązanego z bazą danych do viewmodelu to jedna z najgorszych rzeczy jaką możesz zrobić

Dlaczego? A czy we własnych atrybutach można używać połączenia z bazą, czy też się nie powinno?

"własnych atrybutach"? mógłbyś rozwinąć co masz na myśli? - WeiXiao 2018-11-25 19:39
klasy dziedziczące po ValidationAttribute - panDawid 2018-11-25 19:45

Pozostało 580 znaków

2018-11-25 19:59
1

W sumie rzuciłem te customowe ValidationAttribute jako przykład jak to należy zrobić (bo można: ValidationAttribute.IsValid() daje ci ValidationContext, w którym możesz zrobić GetService<T>(), aby uzyskać obiekt jaki ci trzeba, np. DbContext), tymczasem:

Validation Attributes like StringLength, RegularExpression, Required and such validations are examples of good attributes and Validation Attributes that checks for uniqness or other database related rules are examples of inappropriate attributes.

Za https://stackoverflow.com/a/32172401, rozwinięcie w https://stackoverflow.com/que[...]sses#comment52231722_32172401:

(...) In cases that the system must prevent duplicate data, it is better to do this in your Business Logic codes.

Jednocześnie wygląda na to, że społeczność jest podzielona, bo są wątki, że OK, ale użyj FluentValidation: https://stackoverflow.com/que[...]operty-in-model-best-practice, ale też ktoś zrobił to jako atrybut https://github.com/fatihBulbul/UniqueAttribute

Pozostało 580 znaków

2018-11-25 22:04
._.
0

Jaki jest sens używania ViewModeli do walidacji? Przecież zdaniem modelu domeny jest zapewnienie takiego kontraktu dla klientów a by przekazany typ był prawidłowy, a nie na odwrót. Najlepszym podejściem jest wystawienie metody Validate w encji.

Pozostało 580 znaków

2018-11-25 23:05
0

Moim zdaniem taki jest sens, że wówczas walidacja przeprowadzona jest w jednym miejscu, a nie część właściwości walidowanych jest za pomocą atrybutów, potem dodatkowo jeszcze walidacja tych samych właściwości przeprowadzana jest w encji, a potem kolejne właściwości walidowane są w kolejnej encji (jeśli w ViewModelu są dane z dwóch tabel) itd.

Pozostało 580 znaków

2018-11-25 23:44
1

@panDawid: dwa pytanka:

  1. Dlaczego Twoim zdaniem warstwa prezentacji powinna cokolwiek wiedzieć o bazie danych?
  2. Jak przetestujesz jednostkowo taką walidację?

"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

2018-11-26 00:33
0

Dlaczego Twoim zdaniem warstwa prezentacji powinna cokolwiek wiedzieć o bazie danych?

Z postów wyżej dowiedziałem się, że jednak ani w ViewModelach, ani w ValidationAttribute nie powinno być komunikacji z bazą danych. Wcześniej po prostu nie sądziłem, że to jest źle. Nie mniej jednak, myślę, że walidacja danych powinna odbywać się w warstwie logiki aplikacji, a nie trochę tu, trochę w encjach. Jeśli zajdzie potrzeba użycia bazy danych do walidacji to myślę że dobrym rozwiązaniem jest coś na wzór tego, a nie tworzenie metod służących jedynie stricte do walidacji. Jeśli mój tok rozumowania jest zły, to popraw mnie proszę :)

Jak przetestujesz jednostkowo taką walidację?

Dawno nie pisałem testów jednostkowych, więc zagrożeń z tej strony nie dostrzegam.

edytowany 1x, ostatnio: panDawid, 2018-11-26 00:43

Pozostało 580 znaków

2018-11-26 03:50
2
panDawid napisał(a):

Z postów wyżej dowiedziałem się, że jednak ani w ViewModelach, ani w ValidationAttribute nie powinno być komunikacji z bazą danych. Wcześniej po prostu nie sądziłem, że to jest źle. Nie mniej jednak, myślę, że walidacja danych powinna odbywać się w warstwie logiki aplikacji

Ale to nie jest warstwa logiki aplikacji, to jest warstwa prezentacji. I o wszem, tam powinna być walidacja, ale tylko danych wprowadzanych przez użytkownika. To jest miejsce na sprawdzenie, czy np. nazwa użytkownika ma więcej niż 6, a mniej niż 20 znaków, i czy nie zawiera spacji - czyli walidacje małe i szybkie, pozwalające dać szybką odpowiedź użytkownikowi, i łatwe do zweryfikowania (czyli przetestowania jednostkowo).

a nie trochę tu, trochę w encjach.

A jak wprowadzisz system płatności, to napiszesz sobie atrybut walidacji sprawdzający środki na koncie?
Nie wszystko da się sprawdzić, w każdej warstwie.

Jeśli zajdzie potrzeba użycia bazy danych do walidacji to myślę że dobrym rozwiązaniem jest coś na wzór tego

Ja tu widzę wpychanie walidacji bazującej na regułach biznesowych, które do działania wymagają źródła danych. Dla mnie to jest bardzo daleko od dobrego rozwiązania - to tworzenie jednowarstwowego spaghetti.

Dawno nie pisałem testów jednostkowych, więc zagrożeń z tej strony nie dostrzegam.

Nie wiem jak rozumieć tę odpowiedź. :) Nie dostrzegasz zagrożeń, bo nie pamiętasz nawet co może pójść źle, czy po prostu nie masz zamiaru pisać testów wcale? Tak czy siak, to raczej nie jest najlepsze podejście.


"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

2018-11-26 04:46
._.
0

Ale to nie jest warstwa logiki aplikacji, to jest warstwa prezentacji. I o wszem, tam powinna być walidacja, ale tylko danych wprowadzanych przez użytkownika. To jest miejsce na sprawdzenie, czy np. nazwa użytkownika ma więcej niż 6, a mniej niż 20 znaków, i czy nie zawiera spacji - czyli walidacje małe i szybkie, pozwalające dać szybką odpowiedź użytkownikowi, i łatwe do zweryfikowania (czyli przetestowania jednostkowo).

W jaki sposób zapewniasz spójny stan Encji, cze Encja zwraca jakiś notification, albo rzuca wyjątek. Czy wystarcza ci sprawdzenie punktu wejścia.?
Jeśli serwis aplikacyjny używa komend to dlaczego nie mogę zwalidowąć tych komend w warstwie aplikacji.?

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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