Search code examples
c#mediatormediatr

Have a synchronous handler and an asynchronous handler


Please see the synchronous code below:

public class PersonHandler : IRequestHandler<Person, Person>
    {
        public Task<Person> Handle(Person request, CancellationToken cancellationToken)
        {
            request.ID = 1;
            request.Name = "Brian";
            request.Age = 53;
            return Task.FromResult(request);
        }
    }

and the calling code below:

var response2 = mediator.Send(new Person());

This works as expected. Please see the asynchronous code below:

public class PersonHandlerAsync : IRequestHandler<Person, Person>
    {
        public async Task<Person> Handle(Person request, CancellationToken cancellationToken)
        {
            request.ID = 1;
            request.Name = "Brian";
            request.Age = 53;
            var result = await Task.FromResult(request);
            await Task.Delay(30000);
            return result;
        }
    }

and the calling code below:

var response = Task.Run(() => mediator.Send(new Person()));

This code works as expected.

Is it possible to have two handlers for the same class (Person) i.e. one synchronous and the other asynchronous? If I put both handler classes in my code, then both the mediator.send lines i.e. mediator.Send(new Person()); and Task.Run(() => mediator.Send(new Person())); call the synchronous method.

How can I tell mediatr, which handler class to use? i.e. PersonHandler for synchronous calls and PersonHandlerAsync for asynchronous calls.


Solution

  • You can't do it how you've specified.

    Declare whatever flavor of handler you need - sync, async or cancellable async. From the IMediator side, the interface is async-only, designed for modern hosts.

    However, one workaround would be to create a PersonRequest and PersonRequestAsync class, inherited from Person class:

    public class Person
    {
        public int Id {get; set;}
        public string Name {get; set;}
        public int Age {get; set;}
    }
    
    //sync request
    public class PersonRequest : Person, IRequest<Person>
    { }
    
    //async request
    public class PersonRequestAsync : Person, IRequest<Person>
    { }
    

    Then, your handlers could look something like this:

    public class PersonHandler : IRequestHandler<PersonRequest, Person>
    {
        public Task<Person> Handle(Person request, CancellationToken cancellationToken)
        {
            request.ID = 1;
            request.Name = "Brian";
            request.Age = 53;
            return Task.FromResult(request);
        }
    }
    

    And your async handler as follows:

    public class PersonHandlerAsync : IRequestHandler<PersonRequestAsync, Person>
    {
        public async Task<Person> Handle(PersonRequestAsync request, CancellationToken cancellationToken)
        {
            request.ID = 1;
            request.Name = "Brian";
            request.Age = 53;
    
            //not sure what this is? Hopefully it's just here for demo purposes!
            var result = await Task.FromResult(request);
    
            await Task.Delay(30000);
    
            return result;
        }
    }
    

    This effectively ties PersonRequestAsync to PersonHandlerAsync