zoukankan      html  css  js  c++  java
  • 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的具体实现

  • 相关阅读:
    分模块开发创建service子模块——(八)
    分模块开发创建dao子模块——(七)
    分模块开发创建父工程——(六)
    Html设置html与body元素高度问题
    原生JS给元素添加class属性
    【雪花点】雪花点的显示——(二)
    【雪花点】雪花点的显示——(一)
    Dom4j用Xpath获取节点——(六)
    Dom4j向XML中指定位置添加、删除、修改节点——(五)
    [置顶] 详细解读:技术有没有前途之分
  • 原文地址:https://www.cnblogs.com/chucklu/p/13092768.html
Copyright © 2011-2022 走看看