An example of how you can use the new notification API within EPiServer to notify admins that are online that something has gone wrong.
Blogpost can be found here
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Web.Security; | |
| using EPiServer.ContentCollaboration.Notification; | |
| using EPiServer.Notification; | |
| using EPiServer.PlugIn; | |
| using EPiServer.Scheduler; | |
| using EPiServer.ServiceLocation; | |
| [ScheduledPlugIn(DisplayName = "ScheduledNotificationTest")] | |
| public class ScheduledNotificationTest : ScheduledJobBase | |
| { | |
| private bool stopSignaled; | |
| public ScheduledNotificationTest() | |
| { | |
| this.IsStoppable = true; | |
| } | |
| protected Injected<INotifier> Notifier { get; set; } | |
| protected Injected<INotificationProvider> NotificationProvider { get; set; } | |
| protected Injected<INotififcation> Notififcation { get; set; } | |
| protected Injected<IUserNotificationRepository> UserNotificationRepository { get; set; } | |
| /// <summary> | |
| /// Called when a user clicks on Stop for a manually started job, or when ASP.NET shuts down. | |
| /// </summary> | |
| public override void Stop() | |
| { | |
| this.stopSignaled = true; | |
| } | |
| /// <summary> | |
| /// Called when a scheduled job executes | |
| /// </summary> | |
| /// <returns>A status message to be stored in the database log and visible from admin mode</returns> | |
| public override string Execute() | |
| { | |
| //Call OnStatusChanged to periodically notify progress of job for manually started jobs | |
| this.OnStatusChanged(string.Format("Starting execution of {0}", this.GetType())); | |
| //For long running jobs periodically check if stop is signaled and if so stop execution | |
| if (this.stopSignaled) | |
| { | |
| //this.SendMessage("Stop of job was called"); | |
| return "Stop of job was called"; | |
| } | |
| this.SendMessage("Test notification sent."); | |
| return "Completed"; | |
| } | |
| private async void SendMessage(string message) | |
| { | |
| string[] usersInRole = Roles.GetUsersInRole("Administrators"); | |
| INotificationUser notificationSender = new NotificationUser("admin"); | |
| List<INotificationUser> notificationReceivers = (from sUser in usersInRole | |
| select Membership.GetUser(sUser) | |
| into user | |
| where user != null | |
| select new NotificationUser(user.UserName)) | |
| .Cast<INotificationUser>().ToList(); | |
| SlackNotifier notifier = new SlackNotifier(); | |
| await | |
| notifier.PostNotificationAsync( | |
| new NotificationMessage() | |
| { | |
| ChannelName = SlackFormatter.ChannelName, | |
| Content = message, | |
| Subject = "Scheduled job", | |
| Recipients = notificationReceivers, | |
| Sender = notificationSender, | |
| TypeName = SlackMessageProvider.Name | |
| } | |
| ); | |
| await | |
| this.Notifier.Service.PostNotificationAsync( | |
| new NotificationMessage | |
| { | |
| ChannelName = SlackFormatter.ChannelName, | |
| Content = message, | |
| Subject = "Scheduled job", | |
| Recipients = notificationReceivers, | |
| Sender = notificationSender, | |
| TypeName = SlackMessageProvider.Name | |
| } | |
| ); | |
| } | |
| } |
| using System.Collections.Generic; | |
| using EPiServer.Notification; | |
| using EPiServer.ServiceLocation; | |
| /// <summary> | |
| /// Class SlackFormatter. | |
| /// </summary> | |
| /// <seealso cref="EPiServer.Notification.INotificationFormatter" /> | |
| /// <seealso cref="EPiServer.Notification.IUserNotificationFormatter" /> | |
| [ServiceConfiguration(typeof(IUserNotificationFormatter))] | |
| [ServiceConfiguration(typeof(INotificationFormatter))] | |
| public class SlackFormatter : INotificationFormatter, IUserNotificationFormatter | |
| { | |
| /// <summary> | |
| /// The channel name | |
| /// </summary> | |
| public const string ChannelName = "epi.slack"; | |
| /// <summary> | |
| /// The name of the formatter. | |
| /// </summary> | |
| /// <value>The name of the formatter.</value> | |
| public string FormatterName | |
| { | |
| get | |
| { | |
| return "slackformatter"; | |
| } | |
| } | |
| /// <summary> | |
| /// Specifies which channels the formatter supports. | |
| /// </summary> | |
| /// <value>The supported channel names.</value> | |
| public IEnumerable<string> SupportedChannelNames | |
| { | |
| get | |
| { | |
| return new[] { ChannelName }; | |
| } | |
| } | |
| /// <summary> | |
| /// Performs formatting of messages. | |
| /// </summary> | |
| /// <param name="notifications">Messages to format</param> | |
| /// <param name="recipient">The receiver of the message</param> | |
| /// <param name="format">The format to format to</param> | |
| /// <param name="channelName">The message channel</param> | |
| /// <returns>A list of formatted messages</returns> | |
| /// <remarks>One use case for a formatter might be to combine several messages into one.</remarks> | |
| public IEnumerable<FormatterNotificationMessage> FormatMessages( | |
| IEnumerable<FormatterNotificationMessage> notifications, | |
| string recipient, | |
| NotificationFormat format, | |
| string channelName) | |
| { | |
| // we do not want to change the messages, so we just return them as they are | |
| return notifications; | |
| } | |
| /// <summary> | |
| /// Formats the user message. | |
| /// </summary> | |
| /// <param name="notification">The notification.</param> | |
| /// <returns>UserNotificationMessage.</returns> | |
| public UserNotificationMessage FormatUserMessage(UserNotificationMessage notification) | |
| { | |
| if (notification != null) | |
| { | |
| notification.Content = "<div style=\"color:#f7542b\">" + notification.Content + "</div>"; | |
| } | |
| return notification; | |
| } | |
| } |
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using EPiServer.Notification; | |
| using EPiServer.ServiceLocation; | |
| using Slack.Webhooks; | |
| /// <summary> | |
| /// Class SlackMessageProvider. | |
| /// </summary> | |
| /// <seealso cref="EPiServer.Notification.INotificationProvider" /> | |
| /// <seealso cref="EPiServer.Notification.INotificationProviderStatus" /> | |
| [ServiceConfiguration(typeof(INotificationProvider))] | |
| public class SlackMessageProvider : INotificationProvider, INotificationProviderStatus | |
| { | |
| /// <summary> | |
| /// The name | |
| /// </summary> | |
| public const string Name = "Slack"; | |
| /// <summary> | |
| /// The slack client | |
| /// </summary> | |
| private readonly SlackClient slackClient = | |
| new SlackClient("https://your.webhook"); | |
| /// <summary> | |
| /// Gets the name of the provider. | |
| /// </summary> | |
| /// <value>The name of the provider.</value> | |
| public string ProviderName | |
| { | |
| get | |
| { | |
| return Name; | |
| } | |
| } | |
| /// <summary> | |
| /// Specifie the format the provider supports. | |
| /// </summary> | |
| /// <returns>Supported format.</returns> | |
| public NotificationFormat GetProviderFormat() | |
| { | |
| return new NotificationFormat { MaxLength = null, SupportsHtml = false }; | |
| } | |
| /// <summary> | |
| /// Sends the formatted messages. | |
| /// </summary> | |
| /// <param name="messages">The messages to send.</param> | |
| /// <param name="succeededAction">A success action that should be called for successfully sent messages.</param> | |
| /// <param name="failedAction">A failure action that should be called when a message send operation fails.</param> | |
| public void Send( | |
| IEnumerable<ProviderNotificationMessage> messages, | |
| Action<ProviderNotificationMessage> succeededAction, | |
| Action<ProviderNotificationMessage, Exception> failedAction) | |
| { | |
| IEnumerable<ProviderNotificationMessage> notificationMessages = | |
| messages as IList<ProviderNotificationMessage> ?? messages.ToList(); | |
| foreach (ProviderNotificationMessage message in notificationMessages) | |
| { | |
| try | |
| { | |
| SlackMessage slackMessage = new SlackMessage | |
| { | |
| Channel = "#yourchannel", | |
| Text = message.Content, | |
| IconEmoji = null, | |
| Username = "EPi Notification", | |
| Mrkdwn = false | |
| }; | |
| this.slackClient.Post(slackMessage); | |
| if (succeededAction != null) | |
| { | |
| succeededAction(message); | |
| } | |
| } | |
| catch (Exception e) | |
| { | |
| // if the post fails call the failedAction | |
| if (failedAction == null) | |
| { | |
| continue; | |
| } | |
| failedAction(message, e); | |
| } | |
| } | |
| } | |
| /// <summary> | |
| /// Specifies whether or not the provider is disabled | |
| /// </summary> | |
| /// <value><c>true</c> if this instance is disabled; otherwise, <c>false</c>.</value> | |
| public bool IsDisabled | |
| { | |
| get | |
| { | |
| return false; | |
| } | |
| } | |
| /// <summary> | |
| /// The reason that the provider is disabled | |
| /// </summary> | |
| /// <value>The disabled reason.</value> | |
| public string DisabledReason | |
| { | |
| get | |
| { | |
| return "No slack"; | |
| } | |
| } | |
| } |
| using System; | |
| using System.Threading.Tasks; | |
| using EPiServer.Notification; | |
| using Slack.Webhooks; | |
| /// <summary> | |
| /// Class SlackNotifier. | |
| /// </summary> | |
| /// <seealso cref="EPiServer.Notification.INotifier" /> | |
| /// <author>Jeroen Stemerdink</author> | |
| public class SlackNotifier : INotifier | |
| { | |
| private readonly SlackClient slackClient = | |
| new SlackClient("https://your.webhook"); | |
| /// <summary> | |
| /// Sends a message. The delivery of the notification depends on user settings, which | |
| /// <see cref="T:EPiServer.Notification.INotificationFormatter" /> and | |
| /// <see cref="T:EPiServer.Notification.INotificationProvider" /> that are registered. | |
| /// </summary> | |
| /// <param name="notification">The message to send.</param> | |
| public async Task PostNotificationAsync(NotificationMessage notification) | |
| { | |
| SlackMessage slackMessage = new SlackMessage | |
| { | |
| Channel = "#yourchannel", | |
| Text = notification.Content, | |
| IconEmoji = null, | |
| Username = "EPi Notification", | |
| Mrkdwn = false | |
| }; | |
| await this.slackClient.PostAsync(slackMessage); | |
| } | |
| /// <summary>Occurs when a message is notified.</summary> | |
| public event EventHandler<NotificationEventArgs> NotificationPosted; | |
| /// <summary> | |
| /// Occurs when a message is saved. | |
| /// </summary> | |
| public event EventHandler<NotificationEventArgs> NotificationSaved; | |
| /// <summary> | |
| /// Occurs when a message is filtered. | |
| /// </summary> | |
| public event EventHandler<NotificationEventArgs> NotificationFiltered; | |
| /// <summary> | |
| /// Handles the <see cref="E:NotificationPosted" /> event. | |
| /// </summary> | |
| /// <param name="e">The <see cref="NotificationEventArgs" /> instance containing the event data.</param> | |
| protected virtual void OnNotificationPosted(NotificationEventArgs e) | |
| { | |
| EventHandler<NotificationEventArgs> handler = this.NotificationPosted; | |
| if (handler != null) | |
| { | |
| handler(this, e); | |
| } | |
| } | |
| /// <summary> | |
| /// Handles the <see cref="E:NotificationSaved" /> event. | |
| /// </summary> | |
| /// <param name="e">The <see cref="NotificationEventArgs" /> instance containing the event data.</param> | |
| protected virtual void OnNotificationSaved(NotificationEventArgs e) | |
| { | |
| EventHandler<NotificationEventArgs> handler = this.NotificationSaved; | |
| if (handler != null) | |
| { | |
| handler(this, e); | |
| } | |
| } | |
| /// <summary> | |
| /// Handles the <see cref="E:NotificationFiltered" /> event. | |
| /// </summary> | |
| /// <param name="e">The <see cref="NotificationEventArgs" /> instance containing the event data.</param> | |
| protected virtual void OnNotificationFiltered(NotificationEventArgs e) | |
| { | |
| EventHandler<NotificationEventArgs> handler = this.NotificationFiltered; | |
| if (handler != null) | |
| { | |
| handler(this, e); | |
| } | |
| } | |
| } |
| using EPiServer; | |
| using EPiServer.Core; | |
| using EPiServer.DataAbstraction; | |
| using EPiServer.Framework; | |
| using EPiServer.Framework.Initialization; | |
| using EPiServer.Notification; | |
| using EPiServer.Web.Routing; | |
| /// <summary> | |
| /// Create a module that get initialized after the CMS Module has been initialized | |
| /// </summary> | |
| [ModuleDependency(typeof(EPiServer.Web.InitializationModule))] | |
| public class SlackNotifierInitialization : IInitializableModule | |
| { | |
| public void Initialize(InitializationEngine context) | |
| { | |
| INotificationPreferenceRegister preferencesRegister = context.Locate.Advanced.GetInstance<INotificationPreferenceRegister>(); | |
| // register the Slack NotificationProvider to handle all notifications created on the "slack" channel | |
| preferencesRegister.RegisterDefaultPreference( | |
| SlackFormatter.ChannelName, | |
| SlackMessageProvider.Name, | |
| s => s); | |
| } | |
| public void Uninitialize(InitializationEngine context) | |
| { | |
| // remove the event handler when the modules gets un initialized | |
| } | |
| } |