Microsoft Identity Integration Server 2003 Developer Reference

Best Practices for Data Source Extension Exports

This topic provides best programming practices to use when writing a call-based or file-based data source MA extension that is used for exports. A code example demonstrates these practices and shows how to deallocate resources in the event that an export times out.

Deallocating Resources after a Session Times Out

During an export to a connected directory, a problem can occur if the export session times out. In this event, resources are not released for unmanaged objects. Normally, when an export is completed, the EndExport method is called which releases these resources. However, during a timeout, the object on which EndExport is normally called is unreachable.

To mitigate this problem, each class should contain a Destructor that can be called to clean up unmanaged resources in the case where the export times out. The Destructor will contain cleanup code that unloads the application domain and aborts the export.

The points in your extension application where this problem might occur are in the classes that implement the following interfaces:

One thing to keep in mind when using a Destructor is that if there is more than one Destructor in the extension, there is no guarantee that they will be called in a certain order. For that reason, you should not make a reference between two classes that have Destructors on them because one class may be destroyed before the other class can use its resources.

An example of how to use a Destructor and cleanup code is shown in the sample below.

Using the try-finally Statement

Another good practice that you should use in all your extensions is the try-finally block. When you use this statement, any managed resources that are allocated in the try block will be cleaned up in the finally block. You should use the try-finally statement at single function entry points, such as GenerateImportFile or DeliverExportFile.

Example Code for Data Source Extensions Used for Export

The following C# code sample shows how to use a Destructor, a cleanup statement, and a try-finally block.

using System;
using System.IO;
using System.Xml;
using System.Text;
using System.Collections.Specialized;
using Microsoft.MetadirectoryServices;

namespace Miis_CallExport
{
	public class MACallExport :  
		IMAExtensibleFileImport, 
		IMAExtensibleCallExport
	{

		bool m_fInitialized; // Used to indicate if we have initialized resources

		//
		// Constructor
		//
		public MACallExport(
			)
		{
			//
			// TODO: Add constructor logic here
			//

			// Set member variable indicating we have initialized class
			m_fInitialized = true;
	}

		//
		// Destructor
		//
		~MACallExport()
		{
			if (m_fInitialized)
				Cleanup(true);
	}

		//
		//  Generic cleanup function used for import and exports.
		//  Cleanup is always called regardless, even if an
		//  exception is thrown from the import and export interfaces.
		//  It is also called in the case when the function times out.
		//  In this case it is called from the destructor (fFromDestructor 
		//  is set to true) and it should not rely on the 
		//  existence of other object instances, since garbage 
		//  collection is non-deterministic.
		//
		public void Cleanup(
			bool fFromDestructor
			)
		{
			if (!fFromDestructor)
			{
				//
				// TODO: Add cleanup logic.  Member objects of this 
				// class instance can be accessed. 
				//		
		}

			//
			// TODO: Add cleanup logic for unmanaged resources of this class.
			//		

			// Set member variable indicating we have released resources
			m_fInitialized = false;
	}

		public void GenerateImportFile( 
			string					filename, 
			string					connectTo, 
			string					user, 
			string					password, 
			ConfigParameterCollection   configParameters,
			bool						fullImport, 
			TypeDescriptionCollection   types,
			ref string				customData 
			)
		{
			try
			{
				//
				// TODO: Add logic here to create import file
				//
		}
			finally
			{
				//
				// TODO: Add code for import specific cleanup
				//

				//
				// Call cleanup code to deallocate resouces
				//
				Cleanup(false);
		}
	}

		public void BeginExport( 
			string					connectTo, 
			string					user, 
			string					password,
			ConfigParameterCollection   configParameters,
			TypeDescriptionCollection   types
			)
		{
			//
			// TODO: Add code to initialize an export run
			//		
	}

		public void ExportEntry( 
			ModificationType	modificationType, 
			string[]			changedAttributes,
			CSEntry			 csentry 
			)
		{
			//
			// TODO: Add code to export one entry to the target
			//		
	}

		public void EndExport(
			)
		{
			//
			// TODO:  Add code for export specific cleanup
			//

			//
			// Call cleanup code to deallocate resouces
			//
			Cleanup(false);
	}
}
}