MediatR 中介模式


使用MediatR完成基於內存級別的消息發布訂閱

在微服務架構中領域驅動模型中處理領域事件的相關操作

在區分好領域模型后,就拿代碼中來說嘛,用戶領域中添加用戶操作可能或存在跟用戶相關的一些領域事件,在添加用戶的時候會執行相關的領域事件

首先需要添加nuget包 MediatR

MediatR中有幾個對象:IRequest,IRequestHandler,INotificationHandler

具體用法可以看下MediatR github

領域模型需要繼承Entity,里面封裝了 領域事件的相關操作

public abstract class Entity
    {
        int? _requestedHashCode;
        int _Id;
        public virtual int Id
        {
            get
            {
                return _Id;
            }
            protected set
            {
                _Id = value;
            }
        }

        private List<INotification> _domainEvents;
        public IReadOnlyCollection<INotification> DomainEvents => _domainEvents?.AsReadOnly();

        public void AddDomainEvent(INotification eventItem)
        {
            _domainEvents = _domainEvents ?? new List<INotification>();
            _domainEvents.Add(eventItem);
        }

        public void RemoveDomainEvent(INotification eventItem)
        {
            _domainEvents?.Remove(eventItem);
        }

        public void ClearDomainEvents()
        {
            _domainEvents?.Clear();
        }

        public bool IsTransient()
        {
            return this.Id == default(Int32);
        }

        public override bool Equals(object obj)
        {
            if (obj == null || !(obj is Entity))
                return false;

            if (Object.ReferenceEquals(this, obj))
                return true;

            if (this.GetType() != obj.GetType())
                return false;

            Entity item = (Entity)obj;

            if (item.IsTransient() || this.IsTransient())
                return false;
            else
                return item.Id == this.Id;
        }

        public override int GetHashCode()
        {
            if (!IsTransient())
            {
                if (!_requestedHashCode.HasValue)
                    _requestedHashCode = this.Id.GetHashCode() ^ 31; 

                return _requestedHashCode.Value;
            }
            else
                return base.GetHashCode();

        }
        public static bool operator ==(Entity left, Entity right)
        {
            if (Object.Equals(left, null))
                return (Object.Equals(right, null)) ? true : false;
            else
                return left.Equals(right);
        }

        public static bool operator !=(Entity left, Entity right)
        {
            return !(left == right);
        }
    }
Entity

如:添加用戶的時候添加一個默認角色相關的表處理

 public class TbUser : Entity, IAggregateRoot
    {
      
        public string UserName { get; set; }
        public string UserPasswrod { get; set; }
        public string UserPhone { get; set; }
        public string XXXXX { get; set; }
        [NotMapped]
        public List<TbUserRole> TbUserRoles { get; set; }
        public TbUser()
        {
            TbUserRoles = new List<TbUserRole>();
            AddDomainEvent(new UserCreatedEvent() { tbUser = this });
        }


        #region 領域職責  結合領域事件處理 黎又銘
        /*
        如:添加用戶的時候添加默認角色  其實本身是可以直接在業務邏輯中寫的
        有點類是SQL觸發器,添加用戶的時候構建件默認角色信息模型觸發事件添加角色信息  
        
        這里有注意到 實體模型並沒有強制處理表接口的主外鍵關系 只是做了模型對象映射 
        */
        /// <summary>
        /// 添加用戶職責  只構建職責 不處理  處理交友領取事件的Command CommandHandler處理
        /// </summary>
        public void AddDefalutRole(TbUserRole tbUserRole)
        {
            TbUserRoles.Add(tbUserRole);
            //添加默認角色的領域事件
            AddDomainEvent(new UserRoleCreatedEvent() { TbUserRole = tbUserRole });
           
        }



        #endregion

    }
User

先定義一個創建用戶的命令操作: 這里的TbUser是領域時間模型,傳遞數據以及對領域模型事件操作

public class UserCreateCommand : IRequest<TbUser>
    {

        public TbUser tbUser{ get; set; }
    }
public class UserCreateCommandHandler : IRequestHandler<UserCreateCommand, TbUser>
    {


        private IUserRepository _userRepository;

        public UserCreateCommandHandler(IUserRepository userRepository)
        {
            _userRepository = userRepository;
        }


        public async Task<TbUser> Handle(UserCreateCommand request, CancellationToken cancellationToken)
        {
          
            await _userRepository.AddUserAsync(request.tbUser);
            await _userRepository.UnitOfWork.SaveEntitiesAsync();
            return request.tbUser;
        }
    }

這里還需要一個MediatR的擴展,發布領域事件

 static class MediatorExtension
    {
        /// <summary>
        /// 異步處理領域事件
        /// </summary>
        /// <param name="mediator"></param>
        /// <param name="ctx"></param>
        /// <returns></returns>
        public static async Task DispatchDomainEventsAsync(this IMediator mediator, UserDbContext ctx)
        {
            var domainEntities = ctx.ChangeTracker
                .Entries<Entity>()
                .Where(x => x.Entity.DomainEvents != null && x.Entity.DomainEvents.Any());

            var domainEvents = domainEntities
                .SelectMany(x => x.Entity.DomainEvents)
                .ToList();

            domainEntities.ToList()
                .ForEach(entity => entity.Entity.ClearDomainEvents());

            var tasks = domainEvents
                .Select(async (domainEvent) => {
                    await mediator.Publish(domainEvent);
                });

            await Task.WhenAll(tasks);
        }
    }
擴展

下面是訂閱領域事件

 public class UserRoleNotification : INotificationHandler<UserRoleCreatedEvent>
    {
        private IUserRepository _userRepository;
        public UserRoleNotification(IUserRepository userRepository)
        {
            _userRepository = userRepository;
        }
        public async Task Handle(UserRoleCreatedEvent notification, CancellationToken cancellationToken)
        {

            await _userRepository.AddUserRoleAsync(notification.TbUserRole);
        }

 在controller中的使用:

[HttpPost]
        [Route("adduser")]
        public async Task<IActionResult> AddUser([FromBody] TbUser tbUser)
        {
            tbUser.AddDefalutRole(new TbUserRole { RoleId = 1, UserId = 1 });
            var command = new UserCreateCommand() { tbUser = tbUser };
            var result = await _mediator.Send(command);
            return Ok(result);
        }

看下效果

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM