Wysyłanie emaili - dobre praktyki

0

Ostatnio znalazłem taki kod. Nie rozumiem kilku rzeczy:

  1. Po co jest tworzony interfejs IEmailConfiguration? Gdyby klasa EmailConfiguration sama sobie wczytywała wartości z jakiegoś źródła, to miałoby to sens, ale przecież ona te wartości otrzymuje "za darmo" - tzn. nic nie musi robić, aby je wczytać. I czy takie pchanie klasy konfiguracji do warstwy aplikacji jest w porządku? Jak dla mnie, powinno się jej używać jedynie przy rejestrowaniu zależności do skonfigurowania jakiegoś EmailClienta.
  2. Dlaczego SmtpClient nie jest zarejestrowany w kontenerze i wstrzykiwany, tylko tworzony "dynamicznie" za pomocą using? Ma to związek z wydajnością? Czy wywołanie Dispose nie może poczekać? Jeśli użyjemy AddScoped, to przecież taDispose zostanie wywołana tuż po zakończeniu przetwarzania żądania.
  3. Co w ogóle sądzicie o tym kodzie?
0
  1. sam nie wiem, interfejs do klasy konifugracyjnej, która przechowuje tylko proste właściwości to jak dla mnie jakiś WTF
    A co do samego istnienia klasy to jakoś musisz skonfigurować ten EmailService, więc nie widze tutaj problemu. Co byś proponował zamiast tego?

  2. a jaka byłaby zaleta gdyby był wstrzykiwany?

0

@some_ONE: Nie trzeba by było go konfigurować za każdym razem, gdy jest potrzebny w kodzie. Ogólnie to po raz kolejny widzę takie podejście, ale nie wiem o co z tym chodzi ;(

0

Czyli jak by to miało wyglądać zamiast klasy konfiguracyjnej?

EDIT: W ogóle twoja odpowiedź dotyczy punktu 1 czy 2?

0

Zamiast wstrzykiwać obiekt klasy konfiguracji wstrzykiwałoby się SmtpClienta, który wcześniej zostałby skonfigurowany w Startupie czy gdzieś indziej przy użyciu właśnie tego obiektu konfiguracji (chociaż przy takim podejściu istnienie EmailConfiguration chyba nie ma sensu, bo jest używana tylko w jednym miejscu).

2
nobody01 napisał(a):

Ostatnio znalazłem taki kod. Nie rozumiem kilku rzeczy:

  1. Po co jest tworzony interfejs IEmailConfiguration?

No przecież jest napisane: Since we are good programmers we will use an interface too!. :P Osobiście przestałbym czytać po tym zdaniu, tak na wszelki wypadek.

Ogólnie interfejs do konfiguracji to nie jest zły pomysł, tylko jeśli chcemy iść tą drogą, to tam powinny być metody , a nie właściwości z publicznymi setterami. Publiczny setter w interfejsie to jakiś absurd.
Ja bym zrobił raczej interfejs IConfigurationProvider, który by mi zwracał EmailConfiguration jakąś metodą. Ale tylko gdybym musiał, bo tak ogólnie, to konfigurowalny w taki sposób serwis do obsługi emailów nie ma za bardzo dla mnie sensu.

I czy takie pchanie klasy konfiguracji do warstwy aplikacji jest w porządku? Jak dla mnie, powinno się jej używać jedynie przy rejestrowaniu zależności do skonfigurowania jakiegoś EmailClienta.

No właśnie nie. Taki interfejs daje tylko to, że można jednostkowo przetestować kod EmailSerwisu, ale testowanie takiej klasy jednostkowo nie ma przecież żadnego sensu.

  1. Dlaczego SmtpClient nie jest zarejestrowany w kontenerze i wstrzykiwany, tylko tworzony "dynamicznie" za pomocą using?

Wtedy byś wypychał szczegóły implementacji do warstwy aplikacji. Jest to w porządku? ;)
Osobiście bym tak nie robił. Żadnego zysku z tego nie ma, to jakiś szczegół implementacji EmailService. Inne klasy powinny po prostu korzystać z tej klasy, która konfiguruje bibliotekę do obsługi emaili na swoje potrzeby.

Ma to związek z wydajnością? Czy wywołanie Dispose nie może poczekać? Jeśli użyjemy AddScoped, to przecież taDispose zostanie wywołana tuż po zakończeniu przetwarzania żądania.

A jeśli poleci wyjątek, to też zostanie dispose zawołane?

0

Ale mogę wypychać szczegóły implementacji, jeśli korzystam z biblioteki, której prawdopodobieństwo zamiany na inną jest bliskie zeru? Np. jakiś ORM albo Identity (oczywiście przy założeniu, że z Identity korzysta jakaś SecurityService i tylko ona, bo pozostałe klasy korzystają właśnie z tej SecurityService)?

Co do tego wywoływania Dispose po rzuceniu wyjątku, to nie wiem, ale zgaduję, że nie. ;) Tak z ciekawości: co zrobić, jeśli poleci wyjątek, a w kontenerze są zarejestrowane klasy kontekstu/sesji ORMa? Jak wtedy wywołać Dispose?

2
nobody01 napisał(a):

Ale mogę wypychać szczegóły implementacji, jeśli korzystam z biblioteki, której prawdopodobieństwo zamiany na inną jest bliskie zeru? Np. jakiś ORM albo Identity (oczywiście przy założeniu, że z Identity korzysta jakaś SecurityService i tylko ona, bo pozostałe klasy korzystają właśnie z tej SecurityService)?

Możesz, ja Ci przecież nie zabronię. Ale moim zdaniem nie powinno się tak robić. Ja między warstwami przekazuję tylko typy zdefiniowane w aplikacji, nie z zewnętrznych bibliotek.

Tak z ciekawości: co zrobić, jeśli poleci wyjątek, a w kontenerze są zarejestrowane klasy kontekstu/sesji ORMa? Jak wtedy wywołać Dispose?

Ja rejestruję w IoC interceptor, który opakowuje wszystkie klasy operujące na DB i tam w razie wyjątku robię rollback transakcji i sprzątam ORMa.

0
somekind napisał(a):

Możesz, ja Ci przecież nie zabronię. Ale moim zdaniem nie powinno się tak robić. Ja między warstwami przekazuję tylko typy zdefiniowane w aplikacji, nie z zewnętrznych bibliotek.

Oczywiście masz rację. Chodziło mi o to, że niektóre biblioteki zachęcają do rejestrowania ich w IoC, aby można ich było łatwo używać, bez stosowania using i wywoływania "ręcznie" konstruktorów z dużymi liczbami argumentów, i nawet jeśli okrywamy taką bibliotekę abstrakcją, to zarejestrowanie jej w IoC ułatwia życie.

Ja rejestruję w IoC interceptor, który opakowuje wszystkie klasy operujące na DB i tam w razie wyjątku robię rollback transakcji i sprzątam ORMa.

Na to to ja chyba jestem za głupi. Byłaby szansa na jakiś pseudokod w wolnej chwili? ;)

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