Search code examples
aspnetboilerplate

How do I build a generic IEventHandler?


I've read https://aspnetboilerplate.com/Pages/Documents/EventBus-Domain-Events and also ABP's implementation of Entity event handlers https://github.com/aspnetboilerplate/aspnetboilerplate/tree/f10fa5205c780bcc27adfe38aaae631f412eb7df/src/Abp/Events/Bus/Entities

I have spent 8 hours at work trying to find a solution to my issue, but I failed to succeed.

I have certain entities that point to a single entity called DatumStatus, which records certain actions that generate different states, such as: approved, modified, reviewed, archived, etc.

I am trying to generate a generic EventHandler capable of modifying its status based on these actions.

An example based on a algorithm:

EventBus.Trigger(new ApproveEventData{
    Repository = _certainRepository,
    Ids = [1, 4, 5]
});

The handler itself would, in turn, handle this state transition

public void HandleEvent(ApproveEventData eventData)
{
    eventData.Repository.Where(p => p.Id.IsIn(eventData.Ids)).ForEach(p => {
        p.Approved = true;
        p.ApprovalDate = DateTime.Now()
    });
}

The problem is, I need to write a generic ApproveEventData and handler capable of firing the same HandleEvent for every single entities.

The "closest" I got is:

EventBus.Trigger(typeof(ApproveEventData<int>), (IEventData) new ApproveEventData<int> {
    Repository = (IRepository<EntityWithStatus<int>, int>) _entityRepository,
    Ids = selectedIds
});

[Serializable]
public class ApproveEventData<TPrimaryKey> : EventData
{
    public IRepository<EntityWithStatus<TPrimaryKey>, TPrimaryKey> Repository;
    public TPrimaryKey[] Ids;
}

The implementation above failes when casting the repository.

Could someone shed some light? Thanks!


Solution

  • I see two possible approaches.

    1. Rely on covariance and contravariance. You can make the cast succeed by making an interface for EntityWithStatus an interface and making both IEntityWithStatus and IRepository covariant (add out to the generic type definition).

    2. Rely on dynamic and leverage generic type inference. Basically have the Repository be dynamic.

    I'd recommend number 1.