Best Practices for Data Source Extension Exports
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. For more information, see Destructors on the MSDN Library Web site.
The points in your extension application where this problem might occur are in the classes that implement the following interfaces:
Keep in mind 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 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 example below.
Using the try-finally Statement
Another good practice is to use the try-finally block in all your extensions. 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 block at single function entry points, such as GenerateImportFile or DeliverExportFile. For more information, see try-finally on the MSDN Library Web site.
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 resources
//
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 resources
//
Cleanup(false);
}
}
}
Send comments about this topic to Microsoft
Build date: 2/16/2009