1
\$\begingroup\$

I have two modules, Notification which basically contains SignalR hubs and CoreSetup which contains core setup logic in it.

I have a class in CoreSetup module which keeps track of employee location . I want SignalR hubs to be notified and those locations to be on MAP when new data are inserted through Web API. I don't want CoreSetup module to have dependency on SignalR module. This is what I have done currently.

[Route("api/salesman-location")]
[ApiController]
public class SalesmanLocationController : BaseController
{
    private readonly SalesmanLocationService _salesmanLocationService;
    private readonly IHubContext<ChatHub> _hubContext;

    public SalesmanLocationController(SalesmanLocationService salesmanLocationService,IHubContext<ChatHub> hubContext)
    {
        _salesmanLocationService = salesmanLocationService;
        _hubContext = hubContext;
    }

    [Route("save")]
    [HttpPost]
    public IActionResult save([FromBody]List<SalesmanLocationDto> datas)
    {
        try
        {
            _hubContext.Clients.All.SendAsync("SalesManLocationfromHub", datas);
            _salesmanLocationService.save(datas);
            return Ok();
        }
        catch (CustomException ex)
        {
            return ApiResponse.getErrorResponseJson(ex.Message);
        }
        catch (Exception ex)
        {
            return ApiResponse.getErrorResponseJson("Failed to save data.");
        }
    }
}

It works pretty well but I have some logic inside save() method of SalesmanLocationService . It would be great if hub can subscribe to save() method of SalesmanLocationService without SalesmanLocationService knowing anything about Hub.Under some condition, I should not broadcast data through hub.

This is how my interface of SalesmanLocationService looks like:

 public interface SalesmanLocationService
    {
        void save(List<SalesmanLocationDto> datas);
    }

This is the actual implementation of SalesmanLocationService

 public class SalesmanLocationServiceImpl : SalesmanLocationService
    {
        public SalesmanLocationServiceImpl()
        {
        }

        public void save(List<SalesmanLocationDto> datas)
        {
           foreach (var data in datas)
           {
            save(data);
           }
        }

        private void save(SalesmanLocationDto data)
        {
           if(someCondition){
             //broadcast to hub
           }
        }
    }
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Its very much hard coded for that single domain type, SalesmanLocation. I would instead use some kind of event aggregation pattern. The domain fires off these events and the singalr hub listenes to these events.

I have made a singalr library that seamlessly forwards events to signalr. Maybe it can give you some ideas

https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy/wiki

Bascily with my design you would do

private void Save(SalesmanLocationDto dto) 
{
    repository.Save(dto);
    eventAggregator.Publish(new SalesmanLocationSavedEvent{ /* map data from dto */ }); 
}

Its completely decoupled and nor the domain or the signalr parts know about each other

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.