Nopcommerce 之事件机制

Posted 波峰浪尖

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Nopcommerce 之事件机制相关的知识,希望对你有一定的参考价值。

Nop有着完善的事件机制,在框架中也多次用到。比如删除删除电子邮件时删除指定的缓存、更新实体时,更新缓存等。这里用到的是“生产者/消费者”模式,该模式中,定义了对象之间一对多的依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。生产者发布事件,消费者处理事件。

一.相关接口和类:

1.IEventPublisher事件发布接口。

2.EventPublisher实现IEventPublisher的类,主要功能包括发布事件并通知订阅者。

3.IConsumer<T>消费者(事件订阅者)接口。

4.ISubscriptionService订阅者接口,解析所有的订阅者。

5.SubscriptionService的具体实现。

二注册事件:

   如果用户想要侦听事件,就需要注册成为消费者。消费者接口IConsumer<T>为一个泛型接口,里面有一个处理事件的方法。IConsumer<T>接口代码如下:

/// <summary>
    /// 消费者
    /// </summary>
    public interface IConsumer<T>
    {
        void HandleEvent(T eventMessage);
    }

在该框架中,实现IConsumer<T>接口的类很多比如Nop.Admin.Infrastructure.Cache.ModelCacheEventConsumer代码如下:

public partial class ModelCacheEventConsumer : IConsumer<EntityUpdated<UrlRecord>>
    {
        public void HandleEvent(EntityUpdated<UrlRecord> eventMessage)
        {
            throw new NotImplementedException();
        }
        #region KEY
        /// <summary>
        /// Key for widget info
        /// </summary>
        /// <remarks>
        /// {0} : current store ID
        /// {1} : widget zone
        /// {2} : current theme name
        /// </remarks>
        public const string WIDGET_MODEL_KEY = "NopFramework.pres.widget-{0}";
        public const string WIDGET_PATTERN_KEY = "NopFramework.pres.widget";
        #endregion
    }

“HandleEvent”为对应的事件处理方法,可以根据需要处理。实现了“IConsumer<T>”接口就注册成为了订阅者,当有任何消息发布时,就能真听到对应的事件。

三.事件订阅

事件订阅主要就是解析哪些用户订阅了事件,这样当事件发生时,才能准确的发送到指定的用户。订阅接口如下:

/// <summary>
    /// 事件订阅服务
    /// </summary>
    public interface ISubscriptionService
    {
        IList<IConsumer<T>> GetSubscriptions<T>();
    }

该接口只有一个获取一个方法--获取所有注册事件的用户。实现该类具体如下:

/// <summary>
    /// 事件订阅服务
    /// </summary>
    public class SubscriptionService : ISubscriptionService
    {
        public IList<IConsumer<T>> GetSubscriptions<T>()
        {
            return EngineContext.Current.ResolveAll<IConsumer<T>>();//
        }
    }

 

四.事件发布

事件发布接口“IEventPublisher”。该接口只包含一个方法:

 /// <summary>
    /// 事件发布接口
    /// </summary>
    public interface IEventPublisher
    {
        /// <summary>
        /// 事件发布
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="eventMessage"></param>
        void Publish<T>(T eventMessage);
    }

具体的实现如下:

 public class EventPublisher : IEventPublisher
    {
        private readonly ISubscriptionService _subscriptionService;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="subscriptionService"></param>
        public EventPublisher(ISubscriptionService subscriptionService)
        {
            this._subscriptionService = subscriptionService;
        }
        /// <summary>
        /// 发布事件,通知订阅者
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="x"></param>
        /// <param name="eventMessage"></param>
        public virtual void PublishToConsumer<T>(IConsumer<T> x,T eventMessage)
        {
            try
            {
                x.HandleEvent(eventMessage);
            }
            catch (Exception exc)
            {
                var logger= EngineContext.Current.Resolve<ILogger>();
                try
                {
                    logger.Error(exc.Message, exc);
                }
                catch (Exception)
                {
                }
            }
        }
        /// <summary>
        /// 根据位于其程序集中的某个类型找到一个插件描述符
        /// </summary>
        /// <param name="providerType"></param>
        /// <returns></returns>
        protected virtual PluginDescriptor FindPlugin(Type providerType)
        {
            if (providerType == null)
                throw new ArgumentNullException("providerType");

            if (PluginManager.ReferencedPlugins == null)
                return null;
            foreach (var plugin in PluginManager.ReferencedPlugins)
            {
                if (plugin.ReferencedAssembly == null)
                    continue;

                if (plugin.ReferencedAssembly.FullName == providerType.Assembly.FullName)
                    return plugin;
            }

            return null;
        }
        /// <summary>
        /// 发布事件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="eventMessage"></param>
        public virtual void Publish<T>(T eventMessage)
        {
            var subscriptions = _subscriptionService.GetSubscriptions<T>();//查找所有注册事件的用户
            subscriptions.ToList().ForEach(x=>PublishToConsumer(x,eventMessage));
        }
    }

先看下“Publish<T>(T eventMessage)”方法,该方法是由其他方法比如更新或者删除实体后调用,触发事件。然后调用ISubscriptionService 接口的“GetSubscriptions”方法,查找所有注册该接口的事件,之后逐条遍历订阅者,执行“PublishToConsumer”方法,发布事件,通知订阅者,具体的处理,可在“HandleEvent”实现;

以上是关于Nopcommerce 之事件机制的主要内容,如果未能解决你的问题,请参考以下文章

nopCommerce 3.9 大波浪系列 之 可退款的支付宝插件(上)

NopCommerce添加事务机制

我的NopCommerce之旅: 应用启动

[转]NopCommerce之旅: 应用启动

我的NopCommerce之旅: 系统代码结构分析

NopCommerce商城系统中的eventbus