1

I am new to Autofac and I cannot have an example of event subscriber application working. Could you help me model it?

The idea is the following.

I have a REST API controller where clients can POST events (implementations of IDomainEvent)

The controller needs to receive injected ALL the projector classes (event handlers) that will do something with the events.

public class EventsController 
    : Controller
{
    private readonly IEnumerable<IEventHandler> _projectors;

    public EventsController(IEnumerable<IEventHandler> projectors)
    {
        _projectors = projectors;
    }

    [HttpPost("EventA")]
    public IActionResult AddEventA([FromBody]EventA evt)
    {
        foreach (var projector in _projectors)
        {
            projector.Handle(evt);
        }
        return Ok();
    }

    [HttpPost("EventB")]
    public IActionResult AddEventB([FromBody]EventB evt)
    {
        foreach (var projector in _projectors)
        {
            projector.Handle(evt);
        }
        return Ok();
    }
}

And then I have many Projectors (event handlers) that do different things with the events they subscribe to.

public class ProjectorA : IEventHandler<EventA>, IEventHandler<EventB>
{
    private readonly IRepository _repository;

    public ProjectorA(IRepository repository)
    {
        _repository = repository;
    }

    public void Handle(EventA evt)
    {
        // do something with EventA
    }

    public void Handle(EventB evt)
    {
        // do something with EventB
    }
}

public class ProjectorB : IEventHandler<EventA>
{
    private readonly IRepository _repository;

    public ProjectorA(IRepository repository)
    {
        _repository = repository;
    }

    public void Handle(EventA evt)
    {
        // do something with EventA
    }

    // I don't care about EventB so I don't subscribe to it
}

The IEventHandler would be something like this I guess:

public interface IEventHandler<in TDomainEvent>
    : IEventHandler
    where TDomainEvent : IDomainEvent
{
    void Handle(TDomainEvent evt);
}

How to modify this modelling and how to register my projectors in Autofac to use it in a similar way?

Thanks in advance!

Steven
  • 166,672
  • 24
  • 332
  • 435
diegosasw
  • 13,734
  • 16
  • 95
  • 159
  • You might want to consider a more 'generic' model, where you move away from controllers and action methods, but instead map use middleware, e.g. delegating handlers, to extract the event type from the url, and dispatch it directly to an `IEventHandler` by resolving it from Autofac. Take a look at [this repository](https://github.com/dotnetjunkie/solidservices) for inspiration, and especially take a look at this [delegating handler](https://github.com/dotnetjunkie/solidservices/blob/master/src/WebApiService/Code/CommandDelegatingHandler.cs). – Steven Apr 30 '18 at 07:59

1 Answers1

0

If you have only 2 types of Event the easiest way would be to have 2 dependencies

public class EventsController 
    : Controller
{
    private readonly IEnumerable<IEventHandler<EventA>> _Aprojectors;
    private readonly IEnumerable<IEventHandler<EventB>> _Bprojectors;

    public EventsController(IEnumerable<IEventHandler<EventA>> Aprojectors,
                            IEnumerable<IEventHandler<EventB>> Bprojectors)
    {
        _Aprojectors = Aprojectors;
        _Bprojectors = Bprojectors;
    }

    // ...
}

But if you want a generic solution, the easiest way is to create a Generic Repository

public class EventsController<TEvent> 
    : Controller
    where TEvent : IEvent 
{
    private readonly IEnumerable<IEventHandler<TEvent>> _projectors;

    public EventsController(IEnumerable<IEventHandler<Event>> projectors)
    {
        _projectors = projectors;
    }

    [HttpPost()]
    public IActionResult AddEvent([FromBody]TEvent evt)
    {
        foreach (var projector in _projectors)
        {
            projector.Handle(evt);
        }
        return Ok();
    }
}

and declare your EventHandler like this

builder.RegisterType<ProjectorA>().As<IEventHandler<AEvent>>();
builder.RegisterType<ProjectorB>().As<IEventHandler<BEvent>>();

Generic controller is not implemented by default within ASP.net MVC. For ASP.net core, this post https://stackoverflow.com/a/45698048/814735 contains great explanation on how to implement such a generic controller.

Cyril Durand
  • 15,834
  • 5
  • 54
  • 62