kgrzybek / modular-monolith-with-ddd

Full Modular Monolith application with Domain-Driven Design approach.
MIT License
10.82k stars 1.7k forks source link

Autofac Decorator Circular dependency issue in DomainEventsDispatcher #324

Open brunobozic opened 4 months ago

brunobozic commented 4 months ago

I am using an older version of this repo.

In DomainEventsDispatcher when I am trying to publish the event via

var tasks = domainEvents.Select(async domainEvent => { await _mediator.Publish(domainEvent); });

I am getting an Autofac error that does suggest there is a problem with the decorator pattern. The issue supposedly happens between the Dispatcher and the UserCreatedDomainEvent

This will pass:

   using (var scope = _lifetimeScope.BeginLifetimeScope())
   {
       var handler = scope.Resolve<INotificationHandler<UserCreatedNotification>>();
       Console.WriteLine(handler.GetType().FullName);
   }

This will not:

    using (var scope = _lifetimeScope.BeginLifetimeScope())
    {
        var handler = scope.Resolve<INotificationHandler<UserCreatedDomainEvent>>();
        Console.WriteLine(handler.GetType().FullName);
    }

So judging by this MediatR need/wants to resolve the dependency by the UserCreatedNotification, yet _mediator.Publish() takes in IDomainEvent (UserCreatedDomainEvent) and it breaks apart at this point.

My notification class looks like this:

    public class UserCreatedNotification : DomainNotificationBase<UserCreatedDomainEvent>
{
    public string ActivationLink;
    public DateTimeOffset? ActivationLinkGenerated;
    public string Email;
    public string FirstName;
    public string LastName;
    public string Origin;
    public Guid ResourceId;
    public Guid UserId;
    public string UserName;

    [JsonConstructor]
    public UserCreatedNotification(UserCreatedDomainEvent integrationEvent, Guid id) : base(integrationEvent, id)
    {
        UserId = integrationEvent.UserId;
        ActivationLink = integrationEvent.ActivationLink;
        FirstName = integrationEvent.FirstName;
        LastName = integrationEvent.LastName;
        Email = integrationEvent.Email;
        ActivationLinkGenerated = integrationEvent.ActivationLinkGenerated;
        Origin = integrationEvent.Origin;
        ResourceId = integrationEvent.UserResourceId;
    }
}

The domain event like this:

public class UserCreatedDomainEvent : DomainEventBase
{
    public string ActivationLink;
    public DateTimeOffset? ActivationLinkGenerated;
    public Guid? CreatorUserId;
    public DateTimeOffset? DateOfBirth;
    public string Email;
    public string FirstName;
    public string LastName;
    public string Oib;
    public string Origin;
    public Guid UserId;
    public string UserName;
    public Guid UserResourceId;

    public UserCreatedDomainEvent(
        Guid userId
        , string email
        , string userName
        , string firstName
        , string lastName
        , string oib
        , DateTimeOffset? dateOfBirth
        , DateTimeOffset? activationLinkGenerated
        , string activationLink
        , Guid? creatorUserId
        , Guid userResourceId
        , string origin
        , EventTypeEnum typeOfEvent
    )
    {
        Email = email;
        UserName = userName;
        FirstName = firstName;
        LastName = lastName;
        UserId = userId;
        Oib = oib;
        DateOfBirth = dateOfBirth;
        ActivationLinkGenerated = activationLinkGenerated;
        ActivationLink = activationLink;
        CreatorUserId = creatorUserId;
        Origin = origin;
        UserResourceId = userResourceId;
        TypeOfEvent = typeOfEvent;
    }
}

Have you noticed this issue happening between the versions of the repo? It may have something to do with the changes in MediatR and/or Autofac.