Skip to main content
added 263 characters in body
Source Link
Anders
  • 671
  • 1
  • 4
  • 11

edit: You could also lazy build the cache by constructing the ICommandHandler when they are requested someting like

var interface = typeof(ICommandHandler<>).MakeGenericType(cmd.GetType());
var handler = _serviceProvider.GetService(interface) as dynamic;
handler.Handle(cmd as dynamic);      

edit: You could also lazy build the cache by constructing the ICommandHandler when they are requested someting like

var interface = typeof(ICommandHandler<>).MakeGenericType(cmd.GetType());
var handler = _serviceProvider.GetService(interface) as dynamic;
handler.Handle(cmd as dynamic);      
added 1527 characters in body
Source Link
Anders
  • 671
  • 1
  • 4
  • 11

You should treat the Command as only a DTO.

public class Command 
{
   public Foo SomeFoo { get;set; }
}

Then we use a visitor pattern on that dto

public interface ICommandHandler<in TCommand>
{
    Task Handle(TCommand command);
}

edit:I got an downvote which I do not understand, its the most clean solution of the answers. And it does not involve type casting and using IsSubclassOf which in it self violate for example Open/closed principle of SOLID. With my solution you work with the IoC not against it. If you need a service just do

public class SendInvoiceCommandHandler : ICommandHandler<SendInvoiceCommand>
{
   private readonly IInvoiceService _invoiceService;

   public SendInvoiceCommandHandler(IInvoiceService invoiceService) 
   {
      _invoiceService = invoiceService;
   }

   public async Task Handle(SendInvoiceCommand cmd)
   {
      await _invoiceService.Send(cmd.InvoiceId);
   }
}

The implementation of ICommandHandler can freely call any service it want and inject it using its constructor.

At runtime I like to use magic to lookup the handlers so I just do

await _cqsClient.ExeceuteAsync(new SendInvoiceCommand(invoiceId));

If you use resharper I have made a plugin that helps when you build a system on visitor pattern like this. https://plugins.jetbrains.com/plugin/12156-resharpervisitorpatternnavigation

It can navigate directly from a instance of the DTO to the handler through a hot key in resharper.

So you need to have a IoC that can register concrete types more dynamic, some have it build in, other dont. I use the vanilla IoC in .NET Core and have written a extension method to the IServiceCollection.

.AddAllTransient(typeof(ICommandHandler<>), typeof(MyCommandThatPointsOutAssembly))

First parameter point out the interface, and the second one a type in assembly you want to want to scan for concrete types of said interface. I wont show that code. But it scans the assembly and registerer all ICommandHandler<T> it can find. I also register a cache for type look up at the same time. This is used from the command runner class like this

public CommandRunner(IServiceProvider serviceProvider, ILogger<CommandRunner> logger, Dictionary<Type, IEnumerable<RegistrationInfo>> typeScanners)
{
    _serviceProvider = serviceProvider;
    _logger = logger;

    _cache = typeScanners[typeof(ICommandHandler<>)]
        .Union(typeScanners[typeof(IQueryHandler<,>)])
        .ToDictionary(info => info.Interface.GetGenericArguments()[0], info => info.Interface);
}

Basicly I build a cache were the DTO is the key, and the value is the concrete type.

Its super easy to execute the Handler once you have that info

private Task ExecuteCommandInternalAsync(Command cmd, IServiceProvider serviceProvider)
{
    var handler = serviceProvider.GetService(_cache[cmd.GetType()]) as dynamic;
    return handler.Handle(cmd as dynamic);
}

You should treat the Command as only a DTO.

public class Command 
{
   public Foo SomeFoo { get;set; }
}

Then we use a visitor pattern on that dto

public interface ICommandHandler<in TCommand>
{
    Task Handle(TCommand command);
}

edit:I got an downvote which I do not understand, its the most clean solution of the answers. And it does not involve type casting and using IsSubclassOf which in it self violate for example Open/closed principle of SOLID. With my solution you work with the IoC not against it. If you need a service just do

public class SendInvoiceCommandHandler : ICommandHandler<SendInvoiceCommand>
{
   private readonly IInvoiceService _invoiceService;

   public SendInvoiceCommandHandler(IInvoiceService invoiceService) 
   {
      _invoiceService = invoiceService;
   }

   public async Task Handle(SendInvoiceCommand cmd)
   {
      await _invoiceService.Send(cmd.InvoiceId);
   }
}

The implementation of ICommandHandler can freely call any service it want and inject it using its constructor.

At runtime I like to use magic to lookup the handlers so I just do

await _cqsClient.ExeceuteAsync(new SendInvoiceCommand(invoiceId));

If you use resharper I have made a plugin that helps when you build a system on visitor pattern like this. https://plugins.jetbrains.com/plugin/12156-resharpervisitorpatternnavigation

It can navigate directly from a instance of the DTO to the handler through a hot key in resharper.

You should treat the Command as only a DTO.

public class Command 
{
   public Foo SomeFoo { get;set; }
}

Then we use a visitor pattern on that dto

public interface ICommandHandler<in TCommand>
{
    Task Handle(TCommand command);
}

edit:I got an downvote which I do not understand, its the most clean solution of the answers. And it does not involve type casting and using IsSubclassOf which in it self violate for example Open/closed principle of SOLID. With my solution you work with the IoC not against it. If you need a service just do

public class SendInvoiceCommandHandler : ICommandHandler<SendInvoiceCommand>
{
   private readonly IInvoiceService _invoiceService;

   public SendInvoiceCommandHandler(IInvoiceService invoiceService) 
   {
      _invoiceService = invoiceService;
   }

   public async Task Handle(SendInvoiceCommand cmd)
   {
      await _invoiceService.Send(cmd.InvoiceId);
   }
}

The implementation of ICommandHandler can freely call any service it want and inject it using its constructor.

At runtime I like to use magic to lookup the handlers so I just do

await _cqsClient.ExeceuteAsync(new SendInvoiceCommand(invoiceId));

If you use resharper I have made a plugin that helps when you build a system on visitor pattern like this. https://plugins.jetbrains.com/plugin/12156-resharpervisitorpatternnavigation

It can navigate directly from a instance of the DTO to the handler through a hot key in resharper.

So you need to have a IoC that can register concrete types more dynamic, some have it build in, other dont. I use the vanilla IoC in .NET Core and have written a extension method to the IServiceCollection.

.AddAllTransient(typeof(ICommandHandler<>), typeof(MyCommandThatPointsOutAssembly))

First parameter point out the interface, and the second one a type in assembly you want to want to scan for concrete types of said interface. I wont show that code. But it scans the assembly and registerer all ICommandHandler<T> it can find. I also register a cache for type look up at the same time. This is used from the command runner class like this

public CommandRunner(IServiceProvider serviceProvider, ILogger<CommandRunner> logger, Dictionary<Type, IEnumerable<RegistrationInfo>> typeScanners)
{
    _serviceProvider = serviceProvider;
    _logger = logger;

    _cache = typeScanners[typeof(ICommandHandler<>)]
        .Union(typeScanners[typeof(IQueryHandler<,>)])
        .ToDictionary(info => info.Interface.GetGenericArguments()[0], info => info.Interface);
}

Basicly I build a cache were the DTO is the key, and the value is the concrete type.

Its super easy to execute the Handler once you have that info

private Task ExecuteCommandInternalAsync(Command cmd, IServiceProvider serviceProvider)
{
    var handler = serviceProvider.GetService(_cache[cmd.GetType()]) as dynamic;
    return handler.Handle(cmd as dynamic);
}
added 753 characters in body
Source Link
Anders
  • 671
  • 1
  • 4
  • 11

You should treat the Command as only a DTO.

public class Command 
{
   public Foo SomeFoo { get;set; }
}

Then we use a visitor pattern on that dto

public interface ICommandHandler<in TCommand>
{
    Task Handle(TCommand command);
}

edit:I got an downvote which I do not understand, its the most clean solution of the answers. And it does not involve type casting and using IsSubclassOf which in it self violate for example Open/closed principle of SOLID. With my solution you work with the IoC not against it. If you need a service just do

public class SendInvoiceCommandHandler : ICommandHandler<SendInvoiceCommand>
{
   private readonly IInvoiceService _invoiceService;

   public SendInvoiceCommandHandler(IInvoiceService invoiceService) 
   {
      _invoiceService = invoiceService;
   }

   public async Task Handle(SendInvoiceCommand cmd)
   {
      await _invoiceService.Send(cmd.InvoiceId);
   }
}

The implementation of ICommandHandler can freely call any service it want and inject it using its constructor.

At runtime I like to use magic to lookup the handlers so I just do

await _cqsClient.ExeceuteAsync(new SendInvoiceCommand(invoiceId));

If you use resharper I have made a plugin that helps when you build a system on visitor pattern like this. https://plugins.jetbrains.com/plugin/12156-resharpervisitorpatternnavigation

It can navigate directly from a instance of the DTO to the handler through a hot key in resharper.

You should treat the Command as only a DTO.

public class Command 
{
   public Foo SomeFoo { get;set; }
}

Then we use a visitor pattern on that dto

public interface ICommandHandler<in TCommand>
{
    Task Handle(TCommand command);
}

The implementation of ICommandHandler can freely call any service it want and inject it using its constructor.

At runtime I like to use magic to lookup the handlers so I just do

await _cqsClient.ExeceuteAsync(new SendInvoiceCommand(invoiceId));

If you use resharper I have made a plugin that helps when you build a system on visitor pattern like this. https://plugins.jetbrains.com/plugin/12156-resharpervisitorpatternnavigation

It can navigate directly from a instance of the DTO to the handler through a hot key in resharper.

You should treat the Command as only a DTO.

public class Command 
{
   public Foo SomeFoo { get;set; }
}

Then we use a visitor pattern on that dto

public interface ICommandHandler<in TCommand>
{
    Task Handle(TCommand command);
}

edit:I got an downvote which I do not understand, its the most clean solution of the answers. And it does not involve type casting and using IsSubclassOf which in it self violate for example Open/closed principle of SOLID. With my solution you work with the IoC not against it. If you need a service just do

public class SendInvoiceCommandHandler : ICommandHandler<SendInvoiceCommand>
{
   private readonly IInvoiceService _invoiceService;

   public SendInvoiceCommandHandler(IInvoiceService invoiceService) 
   {
      _invoiceService = invoiceService;
   }

   public async Task Handle(SendInvoiceCommand cmd)
   {
      await _invoiceService.Send(cmd.InvoiceId);
   }
}

The implementation of ICommandHandler can freely call any service it want and inject it using its constructor.

At runtime I like to use magic to lookup the handlers so I just do

await _cqsClient.ExeceuteAsync(new SendInvoiceCommand(invoiceId));

If you use resharper I have made a plugin that helps when you build a system on visitor pattern like this. https://plugins.jetbrains.com/plugin/12156-resharpervisitorpatternnavigation

It can navigate directly from a instance of the DTO to the handler through a hot key in resharper.

deleted 6 characters in body
Source Link
Robert Harvey
  • 200.7k
  • 55
  • 470
  • 683
Loading
Source Link
Anders
  • 671
  • 1
  • 4
  • 11
Loading