Five New Optimizely Certifications are Here! Validate your expertise and advance your career with our latest certification exams. Click here to find out more
Five New Optimizely Certifications are Here! Validate your expertise and advance your career with our latest certification exams. Click here to find out more
This topic describes the Episerver event management system API. You can use this system to send events in a load-balanced environment.
The EPiServer.Events.Clients.IEventRegistry interface is the public API of the Episerver event system that lets you send and receive site events in a de-coupled manner. The event system does not have any predefined events when Episerver CMS starts. It is up to the code that wants to send and receive events to register them using the IEventRegistry.Get method. The Get method accepts a GUID event ID, and creates a new event object instance if one was not already created for the event ID. Else, it returns the existing one. It is important to note that the GUID event ID is only important to users of the event system in that it lets different pieces of code identify the same event. The event system has no knowledge of what these events are or who uses them.
The Event class returned from the Get method has the following .NET events that user code can subscribe to:
The following example shows how to set up an event handler for a custom event, including a method for raising a custom event:
//Generate unique id for your event and the raiser
private static readonly Guid RaiserId = new Guid("F080ABD6-9BB0-4DC0-9D95-265472FA1CC6");
private static readonly Guid EventId = new Guid("888B5C89-9B0F-4E67-A3B0-6E660AB9A60F");
public void Initialize(EPiServer.Framework.Initialization.InitializationEngine context)
{
//Set up event handler
var myEvent = EventRegistry.Instance.Get(EventId);
myEvent.Raised += myEvent_Raised;
}
void myEvent_Raised(object sender, EventNotificationEventArgs e)
{
// don't process events locally raised
if (e.RaiserId != RaiserId)
{
//Do something, e.g. invalidate cache
}
}
public void RaiseEvent(string message)
{
EventRegistry.Instance.Get(EventId).Raise(RaiserId, message);
}
In the previous example, a string is sent as event argument, the data for the event. You also can send custom objects as event arguments, as long as you can serialize both using data contract serialization(WCF) and JSON serialization(cloud).
Event arguments should be small and simple classes. For example the maximum message size in Azure is 256 Kb (but due to system overhead, this limit is usually slightly less than 256 Kb). Sending large amounts of data in event arguments does not scale.
Example event argument:
[DataContract]
[EventsServiceKnownType]
public class MyEventData
{
[DataMember]
public string Message { get; set; }
[DataMember]
public int MyNumber { get; set; }
}
For the built-in WCF-based event provider it is enough to define WCF end-points as described in Configuring events over WCF. To use another event provider, add the provider configuration to the event element in the episerver.framework section of the web.config as the following example shows:
<event defaultProvider="msmq">
<providers>
<add name="msmq" type="MSMQEventProvider.MSMQEventProvider, MSMQEventProvider" />
</providers>
</event>
You can find more providers, such as the Amazon provider and the Azure provider on EPiServer NuGet.
The following example shows a simple event provider that uses MSMQ for message transportation between IIS sites on same machine. This code is not ready for production use, it is only provided as an example of implementing an event provider for an external system.
using EPiServer.Events;
using EPiServer.Events.Providers;
using EPiServer.Framework.Configuration;
using EPiServer.Framework.Initialization;
using EPiServer.ServiceLocation;
using EPiServer.Web;
using EPiServer.Web.Hosting;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Messaging;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MSMQEventProvider
{
#region msmq
public class MSMQEventProvider : EventProvider
{
private const string EPiServerQueueName = "private$\\episerverevents";
MessageQueue _sendQueue;
private static object _sendLock = new object();
IList<Timer> _receiveTimers = new List<Timer>();
TimeSpan _waitTimeout = new TimeSpan(0, 0, 0, 0, 10);
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
base.Initialize(name, config);
//Get all existing EPiServer queues
var queues = MessageQueue.GetPrivateQueuesByMachine(Environment.MachineName)
.Where(q => q.QueueName.StartsWith(EPiServerQueueName));
_sendQueue = queues.SingleOrDefault(q => q.QueueName.EndsWith(CurrentApplicationId));
if (_sendQueue == null)
{
string queuePath = ".\\" + EPiServerQueueName + CurrentApplicationId;
_sendQueue = MessageQueue.Create(queuePath);
_sendQueue.SetPermissions("Everyone", MessageQueueAccessRights.FullControl);
_sendQueue.Formatter = new BinaryMessageFormatter();
}
//Set up recieve listners for all other queues
foreach (var queue in queues.Where(q => !q.QueueName.EndsWith(CurrentApplicationId)))
{
queue.Formatter = new BinaryMessageFormatter();
_receiveTimers.Add(new Timer(new TimerCallback(Receive), queue, 0, 1000));
}
}
public override void Uninitialize()
{
base.Uninitialize();
foreach (var timer in _receiveTimers)
{
timer.Dispose();
}
_sendQueue.Dispose();
}
public override void SendMessage(EventMessage message)
{
lock (_sendLock)
{
_sendQueue.Send(message);
}
}
private void Receive(object state)
{
MessageQueue queue = state as MessageQueue;
Message message = null;
//Receive throws for empty queue therefore the check with enumerator
while (!IsQueueEmpty(queue))
{
message = queue.Receive(_waitTimeout);
OnMessageReceived(new EventMessageEventArgs(message.Body as EventMessage));
}
}
private bool IsQueueEmpty(MessageQueue queue)
{
using (MessageEnumerator enumerator = queue.GetMessageEnumerator2())
{
return !enumerator.MoveNext();
}
}
private string CurrentApplicationId
{
get { return GenericHostingEnvironment.Instance.ApplicationID.Replace('/', '_').ToLower(); }
}
}
#endregion
}
Last updated: Sep 21, 2015