How to: Log Notification Events
This topic contains a sample that illustrates how to use theForefront Identity Manager Certificate Management (FIM CM) notification API to perform very simple event logging.
CertificateNotificationSinks Sample
The CertificateNotificationSinks
namespace in this example implements classes for various different event types using the notification API to subscribe to events of one type per class; for instance, the OnInstallCertificate
class subscribes to events of the type InstallCertificate, an event that is fired whenever a certificate is installed.
When an event is fired, the Notify function of the appropriate class passes the notification object to a custom EventLogger
object via the HandleEvent
method. The HandleEvent
method then logs some data regarding the event to a file.
Each class implemented in the CertificateNotificationSinks
namespace has a corresponding registry entry in the FIM CM Web.config file. For instance, here is the entry for the OnInstallCertificate
class:
<ClmNotifications>
<add event="InstallCertificate" class="Contoso.Clm.Test.CertificateNotificationSinks.OnInstallCertificate, Contoso.Clm.Test.CustomNotificationSinks" initializationData="C:\logs\InstallCertificateEvents.xml"/>
</ClmNotifications>
CertificateNotificationSinks
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Clm.Shared;
using Microsoft.Clm.Shared.Requests;
using Microsoft.Clm.Shared.ProfileTemplates;
using Microsoft.Clm.Shared.Notifications;
namespace Contoso.Clm.Test.CertificateNotificationSinks
{
class OnInstallCertificate : INotificationSink
{
string fileName;
#region INotificationSink Members
void INotificationSink.Initialize(string data)
{
fileName = data;
}
void INotificationSink.Notify(Notification notification)
{
if (notification.NotificationType != NotificationType.InstallCertificate)
throw new ApplicationException("Invalid notification received");
EventLogger.HandleEvent(notification, fileName);
}
#endregion
}
class OnRevokeCertificate : INotificationSink
{
string fileName;
#region INotificationSink Members
void INotificationSink.Initialize(string data)
{
fileName = data;
}
void INotificationSink.Notify(Notification notification)
{
if (notification.NotificationType != NotificationType.RevokeCertificate)
throw new ApplicationException("Invalid notification received");
EventLogger.HandleEvent(notification, fileName);
}
#endregion
}
class OnRevokeCertificatesOperationCompleted : INotificationSink
{
string fileName;
#region INotificationSink Members
void INotificationSink.Initialize(string data)
{
fileName = data;
}
void INotificationSink.Notify(Notification notification)
{
if (notification.NotificationType != NotificationType.RevokeCertificatesOperationCompleted)
throw new ApplicationException("Invalid notification received");
EventLogger.HandleEvent(notification, fileName);
}
#endregion
}
class OnRequestCertificatesOperationCompleted : INotificationSink
{
string fileName;
#region INotificationSink Members
void INotificationSink.Initialize(string data)
{
fileName = data;
}
void INotificationSink.Notify(Notification notification)
{
if (notification.NotificationType != NotificationType.RequestCertificatesOperationCompleted)
throw new ApplicationException("Invalid notification received");
EventLogger.HandleEvent(notification, fileName);
}
#endregion
}
class OnDownloadPfx : INotificationSink
{
string fileName;
#region INotificationSink Members
void INotificationSink.Initialize(string data)
{
fileName = data;
}
void INotificationSink.Notify(Notification notification)
{
if (notification.NotificationType != NotificationType.DownloadPfx)
throw new ApplicationException("Invalid notification received");
EventLogger.HandleEvent(notification, fileName);
}
#endregion
}
class OnDownloadRawCertificate : INotificationSink
{
string fileName;
#region INotificationSink Members
void INotificationSink.Initialize(string data)
{
fileName = data;
}
void INotificationSink.Notify(Notification notification)
{
if (notification.NotificationType != NotificationType.DownloadRawCertificate)
throw new ApplicationException("Invalid notification received");
EventLogger.HandleEvent(notification, fileName);
}
#endregion
}
}
EventLogger
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using Microsoft.Clm.Shared.Notifications;
using Microsoft.Clm.Shared.Requests;
namespace Contoso.Clm.Test
{
internal static class EventLogger
{
const string XmlData = "\r\n<MethodName>{7}</MethodName>\r\n<RequestID>{0}</RequestID>\r\n<RequestType>{1}</RequestType>\r\n<EventName>{2}</EventName>\r\n<OldProfileUuid>{3}</OldProfileUuid>\r\n<OldSmartCardUuid>{4}</OldSmartCardUuid>\r\n<NewProfileUuid>{5}</NewProfileUuid>\r\n<NewSmartCardUuid>{6}</NewSmartCardUuid>\r\n";
public static void HandleEvent(Notification notification, string fileName)
{
WriteToFile(notification.NotificationType,
notification.Request,
notification.ActorUserUuid,
notification.IsSuccess, fileName);
}
public static void WriteToFile(NotificationType action,
Request request,
Guid actorUuid,
bool isSuccess,
string fileName)
{
try
{
string methodName = GetStackMethod(7);
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
if (File.Exists(fileName))
{
doc.Load(fileName);
System.Diagnostics.Trace.WriteLine("Loading document" + doc.InnerXml);
}
else
{
XmlDeclaration elem = doc.CreateXmlDeclaration("1.0", "utf-16", string.Empty);
doc.AppendChild(elem);
XmlNode root = doc.CreateNode(XmlNodeType.Element, "EventSubscribers", "");
doc.AppendChild(root);
XmlNode sub = doc.CreateNode(XmlNodeType.Element, "Events", "");
root.AppendChild(sub);
}
System.Diagnostics.Trace.WriteLine("Creating event node");
XmlNode node = doc.CreateNode(XmlNodeType.Element, "EventData", "");
node.InnerXml = string.Format(XmlData,
request.Uuid,
request.RequestType.ToString(),
action.ToString(),
request.OldProfileUuid.ToString(),
request.OldSmartcardUuid.ToString(),
request.NewProfileUuid.ToString(),
request.NewSmartcardUuid.ToString(),
methodName);
XmlNode events = doc.SelectSingleNode("descendant::Events");
events.AppendChild(node);
System.Diagnostics.Trace.WriteLine("Saving doc");
doc.Save(fileName);
}
catch(Exception ex)
{
System.Diagnostics.Trace.WriteLine("Unable to insert event" + ex.ToString());
}
}
public static void LogEvent()
{
}
/// <summary>
/// Get the name of a method on the call stack
/// </summary>
/// <param name="stackFrameNumber">0 = GetStackMethodName, 1 = calling method, 2 = the one that call the calling method, etc.</param>
/// <returns>The method name</returns>
private static string GetStackMethod(int stackFrameNumber)
{
for (int i = 0; i < 100; i++)
{
try
{
System.Diagnostics.StackFrame sf1 = new System.Diagnostics.StackFrame(i);
System.Diagnostics.Trace.WriteLine(i + ":" + sf1.GetMethod().Name);
}
catch
{
break;
}
}
System.Diagnostics.StackFrame sf = new System.Diagnostics.StackFrame(stackFrameNumber);
return sf.GetMethod().Name;
}
}
}