dimanche 20 septembre 2020

Avoid switch case in Event Dispatcher to call corresponding Event Handler

We have more than 15 event handlers corresponding to each event type. I want to avoid below switch case in Event Dispatcher to call corresponding event handler based on the event type.

Here is my Event Dispatcher class:

public class EventDispatcher : IEventDispatcher
    {
        private readonly IServiceProvider _serviceProvider;
        public EventDispatcher(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        public async Task<ResultDto> HandleEvent(IEvent @event, ILogger logger)
        {
            ResultDto resultDto = null;
            switch (@event.EventType)
            {
                case EventType.CARD_BLOCK:
                    resultDto = await HandleAsync<CardBlockedEvent>(@event as CardBlockedEvent, logger);
                    break;
                case EventType.CARD_UNBLOCK:
                    resultDto = await HandleAsync<CardUnBlockedEvent>(@event as CardUnBlockedEvent, logger);
                    break;
                case EventType.CARD_CANCEL:
                    resultDto = await HandleAsync<CardCancelledEvent>(@event as CardCancelledEvent, logger);
                    break;
                case EventType.CARD_GROUP_CHANGED:
                    resultDto = await HandleAsync<CardGroupChangedEvent>(@event as CardGroupChangedEvent, logger);
                    break;
                case EventType.CARD_EXPIRY:
                    resultDto = await HandleAsync<CardExpiredEvent>(@event as CardExpiredEvent, logger);
                    break;
                default:
                    logger.Warning($"Unknown event type");
                    resultDto = new ResultDto { ResultType = ResultType.Failure, Message = "Unknown event type" };
                    break;
            }
            return resultDto;
        }
        private async Task<ResultDto> HandleAsync<TEvent>(TEvent @event, ILogger logger) where TEvent : IEvent
        {
            var handler = _serviceProvider.GetService(typeof(IEventHandler<ResultDto, TEvent>)) as IEventHandler<ResultDto, TEvent>;
            return await handler.HandleAsync(@event, logger);
        }

    } 

Below is the Dependency Registrations:

 public class EventHandlerIoCRegistrations : IRegisterSevices
    {
        public void RegisterServicesWith(IServiceCollection serviceCollection)
        {
            RegisterDispatcher(serviceCollection);
            RegisterHandlers(serviceCollection);
        }
        private void RegisterDispatcher(IServiceCollection serviceCollection)
        {
            serviceCollection.AddTransient<IEventDispatcher, EventDispatcher>();
        }

        private void RegisterHandlers(IServiceCollection serviceCollection)
        {
            Assembly.GetExecutingAssembly()
            .GetTypes()
            .Where(item => item.GetInterfaces()
            .Where(i => i.IsGenericType).Any(i => i.GetGenericTypeDefinition() == typeof(IEventHandler<,>)) && !item.IsAbstract && !item.IsInterface)
            .ToList()
            .ForEach(assignedTypes =>
            {
                var serviceType = assignedTypes.GetInterfaces().First(i => i.GetGenericTypeDefinition() == typeof(IEventHandler<,>));
                serviceCollection.AddScoped(serviceType, assignedTypes);

            });
        }
    }

Below is the Event handler interface:

public interface IEventHandler<TResult, TEvent>
        where TEvent : IEvent
        where TResult : class
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="event"></param>
        /// <param name="logger"></param>
        /// <returns></returns>
        Task<TResult> HandleAsync(TEvent @event, ILogger logger);
    }

Is there any better way to do and to avoid this switch case? Any thoughts?

Aucun commentaire:

Enregistrer un commentaire