| | | 1 | | using System.Diagnostics.CodeAnalysis; |
| | | 2 | | using System.Reflection; |
| | | 3 | | using System.Runtime.ExceptionServices; |
| | | 4 | | using Elsa.Mediator.Contracts; |
| | | 5 | | using Elsa.Mediator.Middleware.Command; |
| | | 6 | | using Elsa.Mediator.Middleware.Notification; |
| | | 7 | | using Elsa.Mediator.Models; |
| | | 8 | | |
| | | 9 | | namespace Elsa.Mediator.Extensions; |
| | | 10 | | |
| | | 11 | | /// <summary> |
| | | 12 | | /// Contains helper methods for invoking notification handlers. |
| | | 13 | | /// </summary> |
| | | 14 | | public static class HandlerExtensions |
| | | 15 | | { |
| | | 16 | | /// <summary> |
| | | 17 | | /// Gets the handle method for a notification handler of the given notification type. |
| | | 18 | | /// </summary> |
| | | 19 | | /// <param name="notificationType">The notification type.</param> |
| | | 20 | | /// <returns>The handle method.</returns> |
| | | 21 | | public static MethodInfo GetNotificationHandlerMethod(this Type notificationType) |
| | | 22 | | { |
| | 13711 | 23 | | var handlerType = typeof(INotificationHandler<>).MakeGenericType(notificationType); |
| | 13711 | 24 | | return handlerType.GetMethod("HandleAsync")!; |
| | | 25 | | } |
| | | 26 | | |
| | | 27 | | /// <summary> |
| | | 28 | | /// Gets the handle method for a command handler of the given command type. |
| | | 29 | | /// </summary> |
| | | 30 | | /// <param name="commandType">The command type.</param> |
| | | 31 | | /// <returns>The handle method.</returns> |
| | | 32 | | public static MethodInfo GetCommandHandlerMethod([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfac |
| | | 33 | | { |
| | 41 | 34 | | var commandTypeInterfaces = commandType.GetInterfaces(); |
| | 97 | 35 | | var commandTypeInterface = commandTypeInterfaces.FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefiniti |
| | 41 | 36 | | var resultType = commandTypeInterface?.GetGenericArguments()[0] ?? typeof(Unit); |
| | 41 | 37 | | var handlerType = typeof(ICommandHandler<,>).MakeGenericType(commandType, resultType); |
| | 41 | 38 | | return handlerType.GetMethod("HandleAsync")!; |
| | | 39 | | } |
| | | 40 | | |
| | | 41 | | /// <summary> |
| | | 42 | | /// Invokes the given handler for the given notification. |
| | | 43 | | /// </summary> |
| | | 44 | | /// <param name="handler">The handler to invoke.</param> |
| | | 45 | | /// <param name="handleMethod">The handle method.</param> |
| | | 46 | | /// <param name="notificationContext">The notification context containing the notification and cancellation token.</ |
| | | 47 | | public static Task InvokeAsync(this INotificationHandler handler, MethodBase handleMethod, NotificationContext notif |
| | | 48 | | { |
| | 16873 | 49 | | var notification = notificationContext.Notification; |
| | 16873 | 50 | | var cancellationToken = notificationContext.CancellationToken; |
| | 16873 | 51 | | return InvokeAndUnwrap<Task>(handleMethod, handler, [notification, cancellationToken]); |
| | | 52 | | } |
| | | 53 | | |
| | | 54 | | /// <summary> |
| | | 55 | | /// Invokes the given handler for the given command. |
| | | 56 | | /// </summary> |
| | | 57 | | /// <param name="handler">The handler to invoke.</param> |
| | | 58 | | /// <param name="handleMethod">The handle method.</param> |
| | | 59 | | /// <param name="commandContext">The command to handle.</param> |
| | | 60 | | public static Task<TResult> InvokeAsync<TResult>(this ICommandHandler handler, MethodBase handleMethod, CommandConte |
| | | 61 | | { |
| | 41 | 62 | | var command = commandContext.Command; |
| | 41 | 63 | | var cancellationToken = commandContext.CancellationToken; |
| | 41 | 64 | | return InvokeAndUnwrap<Task<TResult>>(handleMethod, handler, [command, cancellationToken]); |
| | | 65 | | } |
| | | 66 | | |
| | | 67 | | /// <summary> |
| | | 68 | | /// Invokes a method via reflection and unwraps any TargetInvocationException to preserve the original exception's s |
| | | 69 | | /// </summary> |
| | | 70 | | private static T InvokeAndUnwrap<T>(MethodBase method, object target, object[] args) where T : Task |
| | | 71 | | { |
| | | 72 | | try |
| | | 73 | | { |
| | 16914 | 74 | | return (T)method.Invoke(target, args)!; |
| | | 75 | | } |
| | 1 | 76 | | catch (TargetInvocationException ex) when (ex.InnerException is not null) |
| | | 77 | | { |
| | 1 | 78 | | ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); |
| | 0 | 79 | | throw; // Unreachable, but required for compiler |
| | | 80 | | } |
| | 16913 | 81 | | } |
| | | 82 | | } |