Event Mechanism of nopCommerce 3.9 Big Wave Series (Producers, Consumers)

1. Introduction of nop event mechanism

Scenario: After successful payment, customers need to send SMS and email to inform them that the order payment is successful (SMS and email are implemented by different modules)

Implementation: 1. Define OrderPaidEvent event for successful payment.

2. Define SMS, mailbox two consumers jointly monitor the OrderPaidEvent event and implement related business.

3. The producer sends an OrderPaidEvent event when the customer pays successfully.

4. After the consumer receives the OrderPaidEvent event, the SMS and Mailbox consumers perform their respective business.

The nop event mechanism uses the producer/consumer model.Producers are only responsible for publishing events, and do not care who handles them. Instead, consumers are only responsible for handling events.How do producers and consumers relate?The nop implementation is very simple, defining an event class through generics, and if both producers and consumers use the same event class, then the association is called a subscription.The part responsible for implementing the event mechanism itself is called a buffer, which is used to decouple the message mechanism.The producer-consumer relationship is one-to-many.The following figure briefly describes the producer-consumer relationship.

2. nop Event Related Interfaces

Producer interface: Nop.Services.Events.IEventPublisher

Consumer interface: Nop.Services.Events.IConsumer<T>

Event Subscription Interface: Nop.Services.Events.ISubscriptionService

The IEventPublisher interface Publish <T> (T eventMessage) method is used to publish events (producers).

The IConsumer <T>interface HandleEvent(T eventMessage) method is used to handle events (consumers).

The relationship between the two is related by a T generic, called an event, or simply the same T type, where the two associate subscriptions successfully.

The ISubscriptionService interface GetSubscriptions<T>() method returns the IList<IConsumer<T> collection, which saves the consumer.

The interface implementation is as follows:

  1 using System;
  2 using System.Linq;
  3 using Nop.Core.Infrastructure;
  4 using Nop.Core.Plugins;
  5 using Nop.Services.Logging;
  6 
  7 namespace Nop.Services.Events
  8 {
  9     /// <summary>
 10     /// Evnt publisher
 11     /// </summary>
 12     public class EventPublisher : IEventPublisher
 13     {
 14         private readonly ISubscriptionService _subscriptionService;
 15 
 16         /// <summary>
 17         /// Ctor
 18         /// </summary>
 19         /// <param name="subscriptionService"></param>
 20         public EventPublisher(ISubscriptionService subscriptionService)
 21         {
 22             _subscriptionService = subscriptionService;
 23         }
 24 
 25         /// <summary>
 26         /// Publish to cunsumer
 27         /// </summary>
 28         /// <typeparam name="T">Type</typeparam>
 29         /// <param name="x">Event consumer</param>
 30         /// <param name="eventMessage">Event message</param>
 31         protected virtual void PublishToConsumer<T>(IConsumer<T> x, T eventMessage)
 32         {
 33             //Ignore not installed plugins
 34             var plugin = FindPlugin(x.GetType());
 35             if (plugin != null && !plugin.Installed)
 36                 return;
 37 
 38             try
 39             {
 40                 //Consumer Processing
 41                 x.HandleEvent(eventMessage);
 42             }
 43             catch (Exception exc)
 44             {
 45                 //log error
 46                 var logger = EngineContext.Current.Resolve<ILogger>();
 47                 //we put in to nested try-catch to prevent possible cyclic (if some error occurs)
 48                 try
 49                 {
 50                     logger.Error(exc.Message, exc);
 51                 }
 52                 catch (Exception)
 53                 {
 54                     //do nothing
 55                 }
 56             }
 57         }
 58 
 59         /// <summary>
 60         /// Find a plugin descriptor by some type which is located into its assembly
 61         /// </summary>
 62         /// <param name="providerType">Provider type</param>
 63         /// <returns>Plugin descriptor</returns>
 64         protected virtual PluginDescriptor FindPlugin(Type providerType)
 65         {
 66             if (providerType == null)
 67                 throw new ArgumentNullException("providerType");
 68 
 69             if (PluginManager.ReferencedPlugins == null)
 70                 return null;
 71 
 72             foreach (var plugin in PluginManager.ReferencedPlugins)
 73             {
 74                 if (plugin.ReferencedAssembly == null)
 75                     continue;
 76 
 77                 if (plugin.ReferencedAssembly.FullName == providerType.Assembly.FullName)
 78                     return plugin;
 79             }
 80 
 81             return null;
 82         }
 83 
 84         /// <summary>
 85         ///Send Events
 86         /// </summary>
 87         /// <typeparam name="T">Type</typeparam>
 88         /// <param name="eventMessage">Event message</param>
 89         public virtual void Publish<T>(T eventMessage)
 90         {
 91             var subscriptions = _subscriptionService.GetSubscriptions<T>();//Get Subscriber
 92             subscriptions.ToList().ForEach(x => PublishToConsumer(x, eventMessage));
 93         }
 94 
 95     }
 96 }
 97 
EventPublisher
  1 using System.Collections.Generic;
  2 using Nop.Core.Infrastructure;
  3 
  4 namespace Nop.Services.Events
  5 {
  6     /// <summary>
  7     ///Event Subscription Service
  8     /// </summary>
  9     public class SubscriptionService : ISubscriptionService
 10     {
 11         /// <summary>
 12         ///Get event subscriptions
 13         /// </summary>
 14         /// <typeparam name="T">Type</typeparam>
 15         /// <returns>Event consumers</returns>
 16         public IList<IConsumer<T>> GetSubscriptions<T>()
 17         {
 18             return EngineContext.Current.ResolveAll<IConsumer<T>>();
 19         }
 20     }
 21 }
 22 

2. Consumer IConsermer <T>Registration

Register all classes that implement the IConsumer <T>interface in the Nop.Web.Framework.DependencyRegistrar at application startup into the ioc container.

A subscription to a message (T) is available through EngineContext.Current.ResolveAll<IConsumer<T>().

  1  //Register Event Consumer
  2             var consumers = typeFinder.FindClassesOfType(typeof(IConsumer<>)).ToList();
  3             foreach (var consumer in consumers)
  4             {
  5                 builder.RegisterType(consumer)
  6                     .As(consumer.FindInterfaces((type, criteria) =>
  7                     {
  8                         var isMatch = type.IsGenericType && ((Type)criteria).IsAssignableFrom(type.GetGenericTypeDefinition());
  9                         return isMatch;
 10                     }, typeof(IConsumer<>)))
 11                     .InstancePerLifetimeScope();
 12             }

3. Creating consumers

In conjunction with the scenario mentioned above, we create a consumer subscribing to OrderPaidEvent events to handle SMS notifications.

Create OrderPaidSMSEventConsumer class

  1 using System;
  2 using Nop.Core;
  3 using Nop.Core.Domain.Orders;
  4 using Nop.Core.Plugins;
  5 using Nop.Services.Events;
  6 using Nop.Services.Orders;
  7 
  8 namespace Nop.Plugin.SMS
  9 {
 10     public class OrderPaidSMSEventConsumer : IConsumer<OrderPaidEvent>
 11     {
 12 
 13         private readonly IOrderService _orderService;
 14 
 15         public OrderPaidSMSEventConsumer(
 16             IOrderService orderService,
 17             IStoreContext storeContext)
 18         {
 19             this._orderService = orderService;
 20             this._storeContext = storeContext;
 21         }
 22 
 23         /// <summary>
 24         ///Event handling.
 25         /// </summary>
 26         /// <param name="eventMessage">The event message.</param>
 27         public void HandleEvent(OrderPaidEvent  eventMessage)
 28         {
 29 
 30             var order = eventMessage.Order;//Get Order
 31 
 32             //Send SMS Notification Code
 33 	    //....................
 34         }
 35     }
 36 }

The OrderPaidSMSEventConsumer class inherits IConsumer<OrderPaidEvent>, which is the event class that maintains the subscription relationship between producers and consumers.The event class name can be customized to represent an event.

  

Next, we create a consumer OrderPaidEmailEventConsumer class for mail processing, which also inherits ICnsumer<OrderPaidEvent>, indicating that we are subscribing to OrderPaidEvent events as well.

  1 using System;
  2 using Nop.Core;
  3 using Nop.Core.Domain.Orders;
  4 using Nop.Core.Plugins;
  5 using Nop.Services.Events;
  6 using Nop.Services.Orders;
  7 
  8 namespace Nop.Plugin.Email
  9 {
 10     public class OrderPaidEmailEventConsumer : IConsumer<OrderPaidEvent>
 11     {
 12 
 13         private readonly IOrderService _orderService;
 14         private readonly IStoreContext _storeContext;
 15 
 16         public OrderPaidEmailEventConsumer(
 17             IOrderService orderService,
 18             IStoreContext storeContext)
 19         {
 20 
 21             this._orderService = orderService;
 22             this._storeContext = storeContext;
 23         }
 24 
 25         /// <summary>
 26         ///Mail handling
 27         /// </summary>
 28         /// <param name="eventMessage">The event message.</param>
 29         public void HandleEvent(OrderPaidEvent eventMessage)
 30         {
 31 
 32 
 33             var order = eventMessage.Order;
 34 
 35             //Send Mail to Notify Customer
 36 	    //............................
 37         }
 38     }
 39 }

4. Production messages

We have created two consumers who have subscribed to the OrderPaidEvent event. Now let's see how we notify consumers when their payments are complete.

In the Nop.Services.OrderProcessingService class

The _eventPublisher.Publish(new OrderPaidEvent(order)) method sends an OrderPaidEvent event.The consumption (SMS, Mail) of the above subscription to the OrderPaidEvent event handles the message.

5. Event collation commonly used in nop

Consumers, mainly caching

Nop.Web.Infrastructure.Cache.ModelCacheEventConsumer: Foreground model correlation

Nop.Admin.Infrastructure.Cache.ModelCacheEventConsumer: Background model correlation

Nop.Services.Discounts.Cache.DiscountEventConsumer: Discount related

Nop.Services.Catalog.Cache.PriceCacheEventConsumer: Price Related

Nop.Services.Customers.Cache.CustomerCacheEventConsumer: Password modification

Producers, the following figure summarizes the incidents that come with the nop 3.9 source code and the classes they belong to, mostly the unrealized consumers.

nop just leaves a place for events where we can expand on second development.

6. Summary

1. Producers need to inherit the IEventPublisher interface.

2. Consumers need to inherit the IConsumer<T>interface.

3. Consumers subscribe to producers through event classes, and subscription implementations refer to the ISubscriptionService interface.

The nop event mechanism is simple to implement, and interested friends can use RabbitMQ to expand their messages.

There are incorrect understandings and incorrect views in the text. Please leave a message and share your common progress.

This article address: http://www.cnblogs.com/yaoshangjin/p/7234522.html

This is an original and reproduced version of Big Wave. Please indicate the source.

Keywords: ASP.NET RabbitMQ

Added by WolfRage on Mon, 10 Jun 2019 20:38:42 +0300