samedi 20 mai 2017

Publish-Subscriber using SimpleInjector IoC

I've been thought about implementing event model in my web app.

The approach I need to implement is:

  1. Get data from DB;
  2. Pass it to Grab method and collect data;
  3. Convert result to my suitable data and build email, log message lists;
  4. Notify user if needed by email service; (after that we need to change bool flag in DB that user was notified)
  5. Write all grabbing logs into some store;
  6. Add grabbed data to DB.

According to this answer I decided to use mentioned sample. But I've stacked upon how to wire up events and pass data that I need to handle. I have a class whish grabs some info from the internet:

public interface IScheduleService
{
    void ParseWebData(int userId);
}

public class ScheduleService : IScheduleService
{
    IQueryHandler<ProductGrabbedInfoByUserQuery, IEnumerable<ProductGrabbedInfo>> GrabberQuery;
    IEventPublisher publisher;

    List<string> logMessages = new List<string>();
    List<string> emailMessages = new List<string>();


    public ScheduleService(IQueryHandler<ProductGrabbedInfoByUserQuery, IEnumerable<ProductGrabbedInfo>> GrabberQuery,
                           IEventPublisher publisher)
    {
        this.GrabberQuery = GrabberQuery;
        this.publisher = publisher;
    }

    public void ParseWebData(int userId)
    {
        // получаем данные из БД
        var qry = new ProductGrabbedInfoByUserQuery { UserId = 1 }; // пока что один юзер
        var data = GrabberQuery.Handle(qry).ToList();
        if (data.Any())
        {
            // собираем информацию
            GrabberEngine ge = new GrabberEngine(BrowserType.Mozilla);
            ge.Grab(data);
            // преобразовываем в наш вид с собиранием логирования и ошибок
            var converted = ConvertFromGrabbedInfo(data);
            // HERE I THINK WE SHOULD CALL publisher.Publish(new GrabbingCompletedEvent{...}) to execute 3 points below:
            // 1. Send email message using List<string> emailMessages info
            // 2. Log messages using List<string> logMessages info
            // 3. add collected data to DB
        }
    }
}

If we need to have event data being maximum small then we need to store some small values:

public class GrabbingCompletedEvent : IDomainEvent
{
    public readonly string JobId;
    public readonly int UserId;

    public GrabbingCompletedEvent(string JobId, int UserId)
    {
        this.JobId = JobId;
        this.UserId = UserId;
    }
}

Ok, then I think we need to create Event handlers:

public class NotifyEmailGrabbingCompletedEventHandler : IEventHandler<GrabbingCompletedEvent>
{
    private IEmailService emailService;
    private readonly ILogger logger;
    private IEnumerable<string> messages;
    private IQueryHandler<GetByPrimaryKeyQuery<User>, User> UserQuery;

    public NotifyEmailGrabbingCompletedEventHandler(IEmailService emailService, 
        ILogger logger, 
        IEnumerable<string> messages, 
        IQueryHandler<GetByPrimaryKeyQuery<User>, User> UserQuery)
    {
        this.emailService = emailService;
        this.logger = logger;
        this.messages = messages;
        this.UserQuery = UserQuery;
    }

    public void Handle(GrabbingCompletedEvent e)
    {
        var user = GetUserInfo(e.UserId);
        emailService.Send(user.Email, string.Join(Environment.NewLine, messages));
        emailService.SetDelivered(true);
    }

    private User GetUserInfo(int userId)
    {
        var cmd = new GetByPrimaryKeyQuery<User> { PK = userId };
        return UserQuery.Handle(cmd);
    }
}

public class LogGrabbingCompletedEventHandler : IEventHandler<GrabbingCompletedEvent>
{
    private readonly ILogger logger;
    private IEnumerable<string> messages;

    public LogGrabbingCompletedEventHandler(ILogger logger, IEnumerable<string> messages)
    {
        this.logger = logger;
        this.messages = messages;
    }

    public void Handle(GrabbingCompletedEvent e)
    {
        foreach (var message in messages)
        {
            this.logger.Log(message);
        }
    }
}

My question is how could I pass logger instances, lists of messages and queryHandlers to current handlers? Am I right to pass such parameters in event handlers constructor? The first variant that came to me was to add this data as properties into event class, but it seems like bad decision. Could you, please explain what design approach would be better for such situation.

Aucun commentaire:

Enregistrer un commentaire