Asp-Net core - Zrób, gdy coś się wydarzy

0

Cześć,
Jak osiągnąć efekt, że aplikacja webowa .net zrobi coś sama gdy zajdzie jakieś zdarzenie.
Dla przykładu - napisałem posta w tym temacie, więc chcę aby każdy obserwujący dostał powiadomienie.
Czy w takim razie w metodzie akcji "AddPostToThread" oprócz dodania tego posta musi być także wywołanie metody która wysyła powiadomienia do obserwujących? To mi trochę źle wygląda, gdyż może dojść do sytuacji, że podaczas dodania posta, musi być zrobione jeszcze wiele innych rzeczy, więc kontroler w swojej metodzie akcji ma zlecać zrobienie tych wszystkich rzeczy?
Czyli w uproszczeniu :

public IActionResult AddPost(){
forumService.AddPost(...);
notificationService.SentNotification(...);
// i tak dalej 
return RedirectToAction(...);
}

Jak sama nazwa metody akcji mówi, Ma ona zajmować się tylko dodanie posta, a nie wieloma innymi rzeczami. Więc jak się w takich sytuacjach zachować?

4

Rzuć okiem na MediatR i INotification. Ogólnie niech kontroler tylko puszcza event, a to co ma być zrobione zostaw handlerom. Jak będzie jedna akcja więcej do wykonania to dopisujesz handler, kod kontrolera się nie zmienia.

2
Kordoba napisał(a):

kontroler w swojej metodzie akcji ma zlecać zrobienie tych wszystkich rzeczy?

Nie, kontroler powinien wywołać metodę jakiegoś serwisu aplikacyjnego, który to wykona (a raczej zleci ich wykonanie innym klasom) wszystkie potrzebne operacje.
Kontroler nie powinien zawierać zbyt wiele logiki ani wywołań, to tylko utrudnia testowanie i utrzymywanie takiego kodu.

Alternatywnie do serwisu aplikacyjnego możesz użyć MediatR jak zaproponowano wyżej, tylko to zapewne będzie wymagało trochę więcej nauki.

1

Trochę podsumuję to co powiedzieli koledzy wyżej. Po pierwsze nie trzymaj logiki biznesowej w kontrolerach, zostaw im tę robotę za którą powinny być odpowiedzialne- obsługa requestów, ich walidacja, zwracanie odpowiednich kodów http itp. Do twojego konkretnego przypadku najlepiej właśnie zastosować wzorzec mediator, chociażby z wykorzystaniem wyżej wymienionej biblioteki MediatR. Kiedy post zostanie utworzony to do mediatora wysyłasz notyfikację implementującą interfejs INotification i możesz mieć wiele handlerów odpowiedzialnych za reagowanie na takie wydarzenie w systemie. Najlepiej aby każdy handler odpowiadał za inną logikę biznesową.

0

Poczytałem trochę o MediatR i mam kilka pytań:

  1. Czy problemem nie jest duża ilość klas typu event (AddedPostEvent, AddedThreadEvent, DeletedThreadEvent itp) lub Query (GetAllThreadsQuery, GetThreadByIdQuery ...). W jaki sposób ograniczyć tworzenie tylu klas?
  2. Wracając do przykładu z pierwszego postu. Lepiej zrobić jeden EventHandler reagujący na zdarzenie "AddedPostEvent" który np zleca wszystkie operacje związane z dodaniem postu(dodanie postu, poinformowanie itp...), czy może wiele Handlerów, każdego odpowiedzialnego za wykonanie konkretnej rzeczy(oddzielnego na dodanie postu, oddzielnego na wysłanie powiadomienia)?
  3. Jeśli chciałbym mieć Handler który reaguje na więcej niż jeden tym zdarzenia (np NotificationHandler ma reagować na dodanie posta i usunięcie posta, a następnie poinformować o tym konkretnych userów)? Dobrym pomysłem jest stworzenie interfejsu INotificationEvent, który będą implementować zdarzenia, dla których ma zostać wysłane powiadomienie?
3
  1. Duża ilość klas rzadko stanowi problem. Nie musisz ich przecież znać na pamięć, a konstruując nazwy w sensowny sposób znajdziesz to czego potrzebujesz.
  2. Masz narzędzie pozwalające na maksymalne rozdzielenie odpowiedzialności, więc korzystaj z tego - niech każdy handler zajmuje się jedna rzeczą.
  3. Handler może implementować wiele INotificationHandler<>.
0

Dzięki wielkie za wytłumaczenie. Zastanawiam się jeszcze na jedną rzeczą- kolejnością w której handlery reagują na dany event. Załóżmy w kontrolerze jest publikowany event dodania posta. Na ten event reagują dwa handlery (dodania posta i informowania). Dla bezpieczeństwa przed informowaniem sprawdzany jest czy dany post na pewno istnieje (może podczas dodawania wystąpił jakiś błąd). W przypadku gdy najpierw zostanie dodany nowy post to wszystko działa, ale co w przypadku gdy najpierw event odbierze handlery informujący?

0

Aa ok, bo ja chciałem do podpiąć do jednego eventa(dodania posta). I w tym wypadku dla jednego eventa wiele rzeczy by się wykonało, gdyż kilka handlerów by obsługiwało ten dany event.
@szydlak
A chodzi ci o to aby w kontrolerze najpierw wysłać command na stworzenie posta i w zależności od response wysłać (lub nie) command na powiadomienie?

0
Kordoba napisał(a):

A chodzi ci o to aby w kontrolerze najpierw wysłać command na stworzenie posta i w zależności od response wysłać (lub nie) command na powiadomienie?

Tak. Tylko nie wysyłasz eventu z poziomu controllera tylko robisz np IRequestPostProcessor i w nim możesz wyslac event. https://codeopinion.com/mediatr-behaviors/

1
Kordoba napisał(a):

Dzięki wielkie za wytłumaczenie. Zastanawiam się jeszcze na jedną rzeczą- kolejnością w której handlery reagują na dany event. Załóżmy w kontrolerze jest publikowany event dodania posta. Na ten event reagują dwa handlery (dodania posta i informowania). Dla bezpieczeństwa przed informowaniem sprawdzany jest czy dany post na pewno istnieje (może podczas dodawania wystąpił jakiś błąd). W przypadku gdy najpierw zostanie dodany nowy post to wszystko działa, ale co w przypadku gdy najpierw event odbierze handlery informujący?

W przypadku kiedy chcesz wykonać jakieś działania sekwencyjnie to nie podpinasz się do określonego zdarzenia dowolną ilością event handlerów tylko tworzysz jeden i on jest odpowiedzialny za wywołanie odpowiedniej sekwencji działań.

I prawdę mówiąc radzę stosować podejście event - handler w relacji 1:1. Dzięki temu ogarnięcie tego co dzieje się w systemie po określonym zdarzeniu jest dużo łatwiejsze.

0

A co sądzicie o takim podejściu, że w handlerze po udanej operacji wysyłamy notyfikacje do odbioru przez wiele handlerów. W przypadku gdy jakaś operacja się powiedzie, wiele innych handlerów wykonuje swoją pracę. Tu na przykładzie logowania, ale myślę aby analogicznie zrobić dodanie posta (i powiadomieniem obserwujących) które było wałkowane w tym wątku.

using DataTransferLayer.DTOs.Identity.User;
using IdentityServices.Services;
using MediatR;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ServiceBus.Handlers.IdentityHandlers
{
    public class LoginUserCommand : IRequest<bool>
    {
        public LoginUserDTO LoginUserDTO { get; set; }
    }

    public class LoginUserHandler : IRequestHandler<LoginUserCommand, bool>
    {
        private readonly UserService _userService;
        private readonly IMediator _mediator;

        public LoginUserHandler(UserService userService, IMediator mediator)
        {
            _userService = userService;
            _mediator = mediator;
        }

        public async Task<bool> Handle(LoginUserCommand request, CancellationToken cancellationToken)
        {
            bool loginSucceeded = _userService.LoginUser(request.LoginUserDTO);
            if (loginSucceeded)
                await _mediator.Publish(new UserLoggedNotification());
            return loginSucceeded;
        }
    }

    public class UserLoggedNotification
    {
        public UserLoggedNotification()
        {
        }
    }
}

0

Ja tam obstawiam przy swoim, i robię w post procesorze.

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