two kinds of messages dispatched by MediatR

https://github.com/jbogard/MediatR/wiki#basics

MediatR是一种进程内消息传递机制。 支持以同步或异步的形式进行请求/响应,命令,查询,通知和事件的消息传递,并通过C#泛型支持消息的智能调度。

Basics

MediatR has two kinds of messages it dispatches:

  • Request/response messages, dispatched to a single handler
  • Notification messages, dispatched to multiple handlers

 

Request/response

https://github.com/jbogard/MediatR/blob/master/test/MediatR.Tests/SendTests.cs

The request/response interface handles both command and query scenarios. First, create a message:

public class Ping : IRequest<string> { }

Next, create a handler:

public class PingHandler : IRequestHandler<Ping, string>
{
    public Task<string> Handle(Ping request, CancellationToken cancellationToken)
    {
        return Task.FromResult("Pong");
    }
}

Finally, send a message through the mediator:

var response = await mediator.Send(new Ping());
Debug.WriteLine(response); // "Pong"

 https://github.com/jbogard/MediatR/blob/master/src/MediatR/Mediator.cs#L29

mediator会找到对应的handler,并且调用Handle方法,返回调用结果

 public Task<TResponse> Send<TResponse>(IRequest<TResponse> request, CancellationToken cancellationToken = default)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            var requestType = request.GetType();

            var handler = (RequestHandlerWrapper<TResponse>)_requestHandlers.GetOrAdd(requestType,
                t => Activator.CreateInstance(typeof(RequestHandlerWrapperImpl<,>).MakeGenericType(requestType, typeof(TResponse))));

            return handler.Handle(request, cancellationToken, _serviceFactory);
        }

 

In the case your message does not require a response消息不需要应答,也就是没有返回值, use the AsyncRequestHandler<TRequest> base class:

public class OneWay : IRequest { }
public class OneWayHandlerWithBaseClass : AsyncRequestHandler<OneWay>
{
    protected override Task Handle(OneWay request, CancellationToken cancellationToken)
    {
        // Twiddle thumbs
    }
}

Or if the request is completely synchronous请求是完全同步的, inherit from the base RequestHandler class:

public class SyncHandler : RequestHandler<Ping, string>
{
    protected override string Handle(Ping request)
    {
        return "Pong";
    }
}

 

Request types

There are two flavors of requests in MediatR - ones that return a value, and ones that do not:

  • IRequest<T> - the request returns a value
  • IRequest - the request does not return a value

To simplify the execution pipeline, IRequest inherits IRequest<Unit> where Unit represents a terminal/ignored return type.

/// <summary>
    /// Represents a void type, since <see cref="System.Void"/> is not a valid return type in C#.
    /// </summary>
    public struct Unit : IEquatable<Unit>, IComparable<Unit>, IComparable

 

Each request type has its own handler interface, as well as some helper base classes:

  • IRequestHandler<T, U> - implement this and return Task<U>
  • RequestHandler<T, U> - inherit this and return U
  public interface IRequestHandler<in TRequest, TResponse>
        where TRequest : IRequest<TResponse>
    {
        /// <summary>
        /// Handles a request
        /// </summary>
        /// <param name="request">The request</param>
        /// <param name="cancellationToken">Cancellation token</param>
        /// <returns>Response from the request</returns>
        Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken);
    }
    public abstract class RequestHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse>
        where TRequest : IRequest<TResponse>
    {
        Task<TResponse> IRequestHandler<TRequest, TResponse>.Handle(TRequest request, CancellationToken cancellationToken)
            => Task.FromResult(Handle(request));

        /// <summary>
        /// Override in a derived class for the handler logic
        /// </summary>
        /// <param name="request">Request</param>
        /// <returns>Response</returns>
        protected abstract TResponse Handle(TRequest request);
    }

 

Then for requests without return values:

  • IRequestHandler<T> - implement this and you will return Task<Unit>.
  • AsyncRequestHandler<T> - inherit this and you will return Task.
  • RequestHandler<T> - inherit this and you will return nothing (void).

 

Notifications

https://github.com/jbogard/MediatR/blob/master/test/MediatR.Tests/PublishTests.cs

For notifications, first create your notification message:

public class Ping : INotification { }

Next, create zero or more handlers for your notification:

public class Pong1 : INotificationHandler<Ping>
{
    public Task Handle(Ping notification, CancellationToken cancellationToken)
    {
        Debug.WriteLine("Pong 1");
        return Task.CompletedTask;
    }
}

public class Pong2 : INotificationHandler<Ping>
{
    public Task Handle(Ping notification, CancellationToken cancellationToken)
    {
        Debug.WriteLine("Pong 2");
        return Task.CompletedTask;
    }
}

Finally, publish your message via the mediator:

await mediator.Publish(new Ping());
  public Task Publish(object notification, CancellationToken cancellationToken = default)
        {
            if (notification == null)
            {
                throw new ArgumentNullException(nameof(notification));
            }
            if (notification is INotification instance)
            {
                return PublishNotification(instance, cancellationToken);
            }

            throw new ArgumentException($"{nameof(notification)} does not implement ${nameof(INotification)}");
        }

  private Task PublishNotification(INotification notification, CancellationToken cancellationToken = default)
        {
            var notificationType = notification.GetType();
            var handler = _notificationHandlers.GetOrAdd(notificationType,
                t => (NotificationHandlerWrapper)Activator.CreateInstance(typeof(NotificationHandlerWrapperImpl<>).MakeGenericType(notificationType)));

            return handler.Handle(notification, cancellationToken, _serviceFactory, PublishCore);
        }

 

 

 

Publish strategies

The default implementation of Publish loops through the notification handlers and awaits each one. This ensures each handler is run after one another.

Depending on your use-case for publishing notifications, you might need a different strategy for handling the notifications. Maybe you want to publish all notifications in parallel, or wrap each notification handler with your own exception handling logic.

A few example implementations can be found in MediatR.Examples.PublishStrategies. This shows four different strategies documented on the PublishStrategy enum.

 

https://www.cnblogs.com/sheng-jie/p/10280336.html

IPipelineBehavior

 

 MeidatR支持按需配置请求管道进行消息处理。即支持在请求处理前和请求处理后添加额外行为。仅需实现以下两个接口,并注册到Ioc容器即可。

  • IRequestPreProcessor 请求处理前接口
  • IRequestPostProcessor<in TRequest, in TResponse> 请求处理后接口

其中IPipelineBehavior的默认实现:RequestPreProcessorBehaviorRequestPostProcessorBehavior分别用来处理所有实现IRequestPreProcessorIRequestPostProcessor接口定义的管道行为。

而处理管道是如何构建的呢?我们来看下RequestHandlerWrapperImpl的具体实现

 

posted @ 2020-06-11 13:48  ChuckLu  阅读(313)  评论(0编辑  收藏  举报