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:

C#  Copy Code
<ClmNotifications>
<add event="InstallCertificate" class="Contoso.Clm.Test.CertificateNotificationSinks.OnInstallCertificate, Contoso.Clm.Test.CustomNotificationSinks" initializationData="C:\logs\InstallCertificateEvents.xml"/>
</ClmNotifications>

CertificateNotificationSinks

C#  Copy Code
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

C#  Copy Code
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;

	}
}
}

See Also