Skip to content

Support Handler method from other assembly for ScanForTypes attribute #60

Closed

Description

@sebastianstudniczek

Recent addition of ScanForTypes attribute is really nice improvement!

I was wondering whether you're willing to support specyfing methods for Handler property that are implemented in other assembly?

This might be usefull for sharing some common registration methods and avoid duplication.

Sample usecase with modular application where each module will register it's own handlers and decorators:

  • First Module
    [ScanForTypes(
        AssignableTo = typeof(ICommandHandler<>),
        Handler = nameof(Extensions.DecorateCommandHandler)
    )]
    [ScanForTypes(
        AssignableTo = typeof(ICommandHandler<,>),
        Handler = nameof(Extensions.DecorateCommandHandlerWithResponse)
    )]
    [ScanForTypes(
        AssignableTo = typeof(IEventHandler<>),
        Handler = nameof(Extensions.DecorateIntegrationEventHandler)
    )]
    private static partial IServiceCollection AddTransactionalProcessing(
        this IServiceCollection services
    );
  • Second Module
    [ScanForTypes(
        AssignableTo = typeof(ICommandHandler<>),
        Handler = nameof(Extensions.DecorateCommandHandler)
    )]
    [ScanForTypes(
        AssignableTo = typeof(ICommandHandler<,>),
        Handler = nameof(Extensions.DecorateCommandHandlerWithResponse)
    )]
    [ScanForTypes(
        AssignableTo = typeof(IEventHandler<>),
        Handler = nameof(Extensions.DecorateIntegrationEventHandler)
    )]
    private static partial IServiceCollection AddTransactionalProcessing(
        this IServiceCollection services
    );
  • Common Module (referenced by First and Second one)
public static class Extensions 
{
    public static void DecorateCommandHandler<THandler, TRequest>(IServiceCollection services)
        where THandler : class, ICommandHandler<TRequest>
        where TRequest : class, ICommand =>
        services.Decorate<IRequestHandler<TRequest>, CommandTransactionDecorator<TRequest>>();

    public static void DecorateCommandHandlerWithResponse<THandler, TRequest, TResult>(
        IServiceCollection services
    )
        where THandler : class, ICommandHandler<TRequest, TResult>
        where TRequest : class, ICommand<TResult> =>
        services.Decorate<
            IRequestHandler<TRequest, TResult>,
            CommandWithResponseTransactionDecorator<TRequest, TResult>
        >();

    public static void DecorateIntegrationEventHandler<THandler, TEvent>(
        IServiceCollection services
    )
        where THandler : class, IEventHandler<TEvent>
        where TEvent : BaseIntegrationEvent =>
        services.Decorate<
            INotificationHandler<TEvent>,
            IntegrationEventTransactionDecorator<TEvent>
        >();
}

Activity

  1. Dreamescaper commented on Apr 24, 2026

    @Dreamescaper
    Owner

    Currently it is possible either with methods proxing to shared ones:

        [ScanForTypes(
             AssignableTo = typeof(ICommandHandler<>), 
             Handler = nameof(DecorateCommandHandler))]
        private static partial IServiceCollection AddTransactionalProcessing(this IServiceCollection services);
    
    	private static void DecorateCommandHandler<T>(IServiceCollection services)
              => Extensions.DecorateCommandHandler<T>(services);

    or via HandlerTemplate:

        [ScanForTypes(
            AssignableTo = typeof(ICommandHandler<>),
            HandlerTemplate = "global::SharedNamespace.Extensions.DecorateCommandHandler<T>(services)"
        )]
        private static partial IServiceCollection AddTransactionalProcessing(
            this IServiceCollection services
        );

    Although - referencing static method from another type might be a valuable addition. It involves analyzing an expression inside of nameof - that contradicts C# semantics a bit (from C# perspective nameof(Extensions.DecorateCommandHandler) and "DecorateCommandHandler" are the same thing). Which is probably not the end of the world.

  2. sebastianstudniczek commented on Apr 24, 2026

    @sebastianstudniczek
    Author

    Maybe it would be easier to add additional property HandlerType or something similar?

  3. Dreamescaper commented on Apr 24, 2026

    @Dreamescaper
    Owner

    I'd prefer not to bload API surface over this, supporting it via nameof should be fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions