2017-07-18 3 views
0

Je veux enregistrer le (médiateur 3)Impossible d'enregistrer IRequestPreProcessors avec Mediatr

public class IdentifyUserTypeCommandHandler : IRequestPreProcessor<RegisterUserCommand> 
{ 
    private readonly IOptions<TecApiOptions> _options; 

    public IdentifyUserTypeCommandHandler(IOptions<TecApiOptions> options) 
    { 
     _options = options; 
    } 

    public async Task Process(RegisterUserCommand request) 
    { 
     request.Type = "internal"; 
     await Task.FromResult(true); 
    } 
} 

IRequestPreProcessor factice suivant Pour ce faire, j'ai ma configuration de conteneur pour carte IRequestPreProcessor à ma mise en œuvre concrète IdentifyUserTypeCommandHandler

 // Pipeline engine used internally to simplify controllers 
     services.AddMediatR(); 
     // Pre-processors 
     services.AddTransient(typeof(IRequestPreProcessor<RegisterUserCommand>), typeof(IdentifyUserTypeCommandHandler)); 

     // Registers command validator 
     services.AddTransient(typeof(IValidator<RegisterUserCommand>), typeof(RegisterUserCommandValidator)); 

     // Registers generic behaviors 
     services.AddTransient(typeof(IPipelineBehavior<,>), typeof(Pipeline<,>)); 
     services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>)); 
     services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>)); 
     services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPreProcessorBehavior<,>)); 

dès que je lance le code, je reçois l'exception suivante

Sy stem.ArgumentException: Type de service générique ouvert 'MediatR.Pipeline.IRequestPreProcessor ` 1 [TRequest]' nécessite l'enregistrement d'un type d'implémentation générique ouvert.

Je souhaite exécuter ce pré-processeur uniquement pour les commandes de type RegisterUserCommand. Une idée sur comment je peux résoudre ce problème?

Pour votre information pour les dossiers,

public class LoggingBehavior<TCommand, TResponse> : IPipelineBehavior<TCommand, TResponse> 
{ 
    private readonly ILogger _logger; 

    public LoggingBehavior(ILoggerFactory loggerFactory) 
    { 
     _logger = loggerFactory?.CreateLogger(typeof(TCommand).Name) ?? throw new ArgumentNullException(nameof(loggerFactory)); 
    } 

    public async Task<TResponse> Handle(TCommand request, RequestHandlerDelegate<TResponse> next) 
    { 
     try 
     { 
      _logger.LogInformation(LoggingEvents.RUN_HANDLER, $"Handling '{typeof(TCommand).Name}'"); 
      var response = await next(); 
      _logger.LogInformation(LoggingEvents.RUN_HANDLER, $"Handled '{typeof(TResponse).Name}'"); 
      return response; 
     } 
     catch (Exception e) 
     { 
      _logger.LogError(
       LoggingEvents.RUN_HANDLER_EXCEPTION, e, 
       $"An error occured while processing pipeline '{GetType().Name}' [{typeof(TCommand).Name} >> {typeof(TResponse).Name}]"); 
      throw; 
     } 
    } 
} 

Merci, Cordialement, Seb

+0

Je m en supposant que 'LoggingBehavior ' et 'ValidationBehavior ' sont des décorateurs. La façon dont vous essayez d'enregistrer ('IPipelineBehavior <,>') les décorateurs mais en les empilant ne fonctionnera pas avec le conteneur .NET Core. Le noyau .NET n'a aucun support pour les décorateurs.Dans le cas d'un enregistrement non générique, cet enregistrement viendra en premier, sinon le dernier enregistrement sera sélectionné, mais il sera cyclique en fonction de lui-même. – Steven

+0

@Steven J'ai vérifié et il semble que mes comportements fonctionnent comme prévu (au moins quand je débogue mon application). J'ai surtout suivi ce qui est mentionné ici >> https://github.com/jbogard/MediatR/wiki/Behaviors – Seb

+0

Ah, je vois, les comportements de pipeline sont _not_ décorateurs. Eh bien, je suis tout à fait en désaccord avec ceci: "C'est une façon plus naturelle d'améliorer le comportement de vos gestionnaires" et ceci est vrai "mieux supporté dans les conteneurs", mais c'est un mauvais argument pour ne pas faire la bonne chose. – Steven

Répondre

0

Alors après avoir parlé au créateur de la lib, il semble que les processeurs pré & post doivent avoir une définition générique.

public class GenericRequestPostProcessor<TRequest, TResponse> : IRequestPostProcessor<TRequest, TResponse> 

OU

public class GenericRequestPreProcessor<TRequest> : IRequestPreProcessor<TRequest> 

src: Examples

Le <TRequest> et <TRequest, TResponse> sont nécessaires lors de la création d'un nouveau processeur pré/post. Maintenant, le 1 000 000 question $ dollars je vais essayer de répondre plus tard:

Comment nous sommes spécialistes de processeurs afin qu'ils traitent avec un ensemble spécifique de demandes/commandes (sans avoir à vérifier le type de demande) ...

0

Si vous utilisez services.AddMediatR()

Assurez-vous d'enregistrer le comportement intégré: RequestPreProcessorBehavior

services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPreProcessorBehavior<,>)); 
services.AddMediatR(); 

Ensuite, votre pré-processeur doit avoir la définition générique par @ réponse de Sébastien:

public class PingDecorator<TRequest> : IRequestPreProcessor<TRequest> 
{ 
    public Task Process(TRequest request) 
    { 
     return Unit.Task; 
    } 
} 

Si vous voulez que votre pré-processeur pour être utilisé avec une demande spécifique:

public class PingDecorator<TRequest> : IRequestPreProcessor<TRequest> where TRequest:Ping 
{ 
    public Task Process(TRequest request) 
    { 
     request.Message = request.Message + " Decorated"; 
     return Unit.Task; 
    } 
}