How to: Create Connected Data Source Extensions for OLEDB Database Access

Note

With the release of ECMA 2.0, this feature has been deprecated and will be removed in future versions. You should use the Extensible Connectivity 2.0 Management Agent Reference for Connector development going forward.

This topic contains a code example that creates a connected data source extension for connecting a database to Forefront Identity Manager Synchronization Service (FIM Synchronization Service) by means of OLE/DB.

This example uses methods of the IMAExtensibleFileImport interface to import data from an XML file, and it uses methods of the IMAExtensibleCallExport interface and the OLEDB Provider to export the information to a Microsoft SQL Server database.

The following code example shows how to create a connected data source extension for call-based data sources.

using System;
using System.IO;
using System.Xml;
using System.Text;
using System.Collections;
using System.Collections.Specialized;
using Microsoft.MetadirectoryServices;
using System.Data; 
using System.Data.SqlClient;  
using System.Data.OleDb;

namespace Miis_CallExport
{
  public class MACallExport :  
  IMAExtensibleFileImport, 
  IMAExtensibleCallExport
  {
  public MACallExport() {}

  // ------------------ C O N S T A N T S ------------------------
  private const string PARAM_SQLTABLENAME = "Table";
  private const string PARAM_SQLWHERECLAUSE = "SQLWhereClause";
  private const string PARAM_SQLDATABASE = "Database";
  private const string PARAM_SQLTIMEOUT = "Timeout";
  private const string PARAM_SQLSECURITY = "Security";
  private const string PARAM_SQLPROVIDER = "Provider";
  // Not needed: private const string 
  // PARAM_ESCAPEANCHOR = "EscapeAnchor";


  // ------------------  I M P O R T  -----------------------------
  //
  private string EscapeStringForImport(string escape)
  {
  if(escape == null)
  return null;

  escape.Replace("\"", "\"\""); 
  return String.Format("\"{0}\"", escape);
  } // EscapeStringForImport

  private string ConstructConnectionString
  (
  string                      connectTo, 
  string                      user, 
  string                      password, 
  ConfigParameterCollection   configParameters
  )
  {
  string connectionString = "";
  if(configParameters[PARAM_SQLSECURITY].Value.ToUpper().Equals
     ("SSPI"))
  {
  connectionString = String.Format("Provider={0};
     Persist Security Info=False;Integrated Security=SSPI;
     Initial Catalog={1};Data Source={2};Connect Timeout={3}",
  configParameters[PARAM_SQLPROVIDER].Value,
  configParameters[PARAM_SQLDATABASE].Value,
  connectTo,
  configParameters[PARAM_SQLTIMEOUT].Value);
  }
  else
  {
  connectionString = String.Format("Provider={0};
     Persist Security Info=False;User ID={1};Password={2};
     Initial Catalog={3};Data Source={4};Connect Timeout={5}",
  configParameters[PARAM_SQLPROVIDER].Value,
  user,
  password,
  configParameters[PARAM_SQLDATABASE].Value,
  connectTo,
  configParameters[PARAM_SQLTIMEOUT].Value);
  }
  return connectionString;
  } //ConstructConnectionString

  public void GenerateImportFile
  ( 
  string                      filename, 
  string                      connectTo, 
  string                      user, 
  string                      password, 
  ConfigParameterCollection   configParameters,
  bool                        fullImport, 
  TypeDescriptionCollection   types,
  ref string                  customData 
  )
  {
  if(!fullImport)
  {
  throw new TerminateRunException
     ("This MA only supports full import"); 
  }

  //---------------------------------------------------------------
  // Construct the columns to select from the SQL table by
  // enumerating through the attributes of the first object type.
  // This assumes that the DB MA schema exposes all attributes 
   // available for all object types.
  //---------------------------------------------------------------
  string sqlColumns = "";
  string objectType = "";
  ArrayList attributeList = new ArrayList();
  foreach(TypeDescription t in types)
  {
  objectType = t.Name; 
  foreach(AttributeDescription a in t.Attributes)
  {
  sqlColumns = sqlColumns + a.Name + ","; 
  attributeList.Add(a.Name);
  }
  break;
  }
  if(sqlColumns.Equals(""))
  {
  throw new TerminateRunException(
     "No attributes in schema definition");
  }
   // Remove last comma.
  sqlColumns = sqlColumns.Substring(0, sqlColumns.Length-1); 

  //----------------------------------------------------------------
  // Construct the SQL Select statement for the intermediate import.
   // file.
  //----------------------------------------------------------------
  string commandString = String.Format("SELECT {0} FROM {1}",
  sqlColumns,
  configParameters[PARAM_SQLTABLENAME].Value);
  try
  {
  if(!configParameters[PARAM_SQLWHERECLAUSE].Value.Equals(""))
  {
  commandString = String.Format("{0} WHERE {1}", commandString, 
     configParameters[PARAM_SQLWHERECLAUSE].Value); 
  }
  }
  // Ignore if the parameter "SQLWhereClause" doesn't exist.
   catch {  }
   
  //----------------------------------------------------------------
  // Construct the connection string and connect to the SQL Server database.
  //----------------------------------------------------------------
  string connectionString = ConstructConnectionString(connectTo, 
   user, password, configParameters);

  OleDbConnection myConnection = new OleDbConnection
    (connectionString);
  OleDbCommand myCommand = new OleDbCommand(commandString, 
     myConnection);

  //--------------------------------------------------------------
  // Open the SQL Server database and create the intermediate file.
  // Note that this code only supports String, Integer, GUID, and 
  // DBNULL values.
  // Further datatypes must be added by extending the code.
  //---------------------------------------------------------------
  myConnection.Open(); 
  OleDbDataReader result = myCommand.ExecuteReader
     (CommandBehavior.CloseConnection);

  StreamWriter stream = new StreamWriter(filename, false, 
     System.Text.Encoding.Unicode);
  while(result.Read())
  {
  for(int i=0; i<result.FieldCount;i++)
  {
  if(result[i] is string)
  stream.WriteLine(String.Format("{0}: {1}", attributeList[i], 
        result[i]));
  else if (result[i] is System.Int64)
  stream.WriteLine(String.Format("{0}: {1}", attributeList[i],  
        result[i]));
  else if(result[i] is System.Guid)
  stream.WriteLine(String.Format("{0}: {{{1}}}", attributeList[i], 
        System.Convert.ToString(result[i])));
  else if (result[i] is System.DBNull)
  ; // no output --> NULL value
  else
  throw new UnexpectedDataException(String.Format
       ("Unknown type in SQL Column: {0}", attributeList[i]));  }
  stream.WriteLine(); // new record, separate by new line
  }
  stream.Close();

  } //GenerateImportFile


  // ------------------  E X P O R T  -------------------------------
  // Globals for Export routines.
  private string ExportConnectionString;
  private string ExportTableName;
  private OleDbConnection ExportConnection;
  private TypeDescriptionCollection ExportTypes;
  // Not needed: private bool ExportEscapeAnchor;

  public void BeginExport
  ( 
  string                      connectTo, 
  string                      user, 
  string                      password,
  ConfigParameterCollection   configParameters,
  TypeDescriptionCollection   types
  )
  {
  //----------------------------------------------------------------
  // Construct the connection string and connect to the SQL Server database.
  //----------------------------------------------------------------
  ExportConnectionString = ConstructConnectionString(connectTo, user, 
     password, configParameters);
  ExportConnection = new OleDbConnection(ExportConnectionString);
  ExportConnection.Open(); 

  // Save Type (Schema) information for later to determine 
   // the anchor for a given object type.
  ExportTypes = types;

  // Save the Database table name ro run the Insert/Update/Deletes.
  ExportTableName = configParameters[PARAM_SQLTABLENAME].Value;

  // Save for later if in the where clause the anchor needs to get 
  // enclosed in ''
   // not needed: ExportEscapeAnchor = configParameters
   // [PARAM_ESCAPEANCHOR].Value.ToLower().Equals("yes") ? 
   // true : false;  
  }

  public void ExportEntry
  ( 
  ModificationType    modificationType, 
  string[]            changedAttributes,
  CSEntry             csentry 
  )
  {
  switch(modificationType)
  {
  case ModificationType.Replace:
  UpdateEntry(changedAttributes, csentry);
  break;

  case ModificationType.Add:
  InsertEntry(changedAttributes, csentry);
  break;

  case ModificationType.Delete:
  DeleteEntry(csentry);
  break;
  }
  } //ExportEntry

  private string EscapeStringForExport(string escape)
  {
  if(escape == null)
  return null;

  return escape.Replace("'", "''");
  } // EscapeStringForExport

  private string GetAnchorAttributeName(CSEntry cs)
  {
  TypeDescription t = ExportTypes[cs.ObjectType]; 
  //-----------------------------------------------------------
  // Note that this MA only supports one Anchor attribute.
  //-----------------------------------------------------------
  if(t.AnchorAttributes.Count > 1) 
  throw new TerminateRunException(String.Format("ObjectType {0} 
     has more than one anchor attribute", cs.ObjectType));

  foreach(AttributeDescription attr in t.AnchorAttributes)
  {
  return attr.Name; 
  }
  return null;
  } // GetAnchorAttributeName

  private bool EscapeAnchorAttribute(CSEntry cs)
  {
  TypeDescription t = ExportTypes[cs.ObjectType]; 
  //-----------------------------------------------------------
  // Note that this MA only supports one Anchor attribute.
  //-----------------------------------------------------------
  if(t.AnchorAttributes.Count > 1) 
  throw new TerminateRunException(String.Format("ObjectType {0} 
     has more than one anchor attribute", cs.ObjectType));

  foreach(AttributeDescription attr in t.AnchorAttributes)
  {
  switch (attr.DataType)
  {
  case AttributeType.String:
  return true;
  case AttributeType.Integer:
  return false;
  case AttributeType.Binary:
  return true;
  default:
  throw new TerminateRunException(String.Format("Anchor type 
       unsupported. ObjectType: {0}, Attribute: {1}, Type: {2}", 
       cs.ObjectType, attr.Name, attr.DataType.ToString()));
  }
  }
  return true;
  } // EscapeAnchorAttribute

  private void UpdateEntry(string[] changedAttributes, CSEntry cs)
  {
  //----------------------------------------------------------------
  // Build the SQL Update Query.
  //----------------------------------------------------------------
  string commandString = String.Format("UPDATE {0} SET", 
     ExportTableName);
  foreach(string attribName in changedAttributes)
  {
  string val = "";
  Attrib attr = cs[attribName]; 
  if(attr.IsPresent)
  {
  switch(attr.DataType)
  {
  case AttributeType.String:
  val = "'" + EscapeStringForExport(attr.StringValue) + "'";
  break;
  case AttributeType.Integer:
  val = System.Convert.ToString(attr.IntegerValue, 10);   
  break;
  default:
  throw new UnexpectedDataException(String.Format("Unknown data 
        type for export update. Attr: {0}, Type: {1}", attribName, 
        attr.DataType.ToString())); 
  }
  }
  else
  {
  val = "NULL";
  }

  commandString = commandString + String.Format(" {0}={1},", 
      attribName, val);
  }
  commandString = commandString.Substring(0, commandString.Length-1); 
   // Remove last comma.

  string anchor = GetAnchorAttributeName(cs);
  string anchorValue = cs[anchor].Value.ToString();
  if(EscapeAnchorAttribute(cs))
  {
  anchorValue = String.Format("'{0}'", anchorValue); 
  }
  commandString = commandString + String.Format(" WHERE {0}={1}", 
    anchor, anchorValue);
  //----------------------------------------------------------------
  // Build the SQL Update Query.
  //----------------------------------------------------------------

  //----------------------------------------------------------------
  // Execute SQL Update Query.
  //----------------------------------------------------------------
  OleDbCommand myCommand = new OleDbCommand(commandString, 
     ExportConnection);
  try { myCommand.ExecuteNonQuery(); }
  catch { throw; } // need better exception to report back the 
     command sent to SQL

  } // UpdateEntry

  private void InsertEntry(string[] changedAttributes, CSEntry cs)
  {
  //---------------------------------------------------------------
  // Build the SQL Insert Query.
  //---------------------------------------------------------------
  string commandString = String.Format("INSERT INTO {0} 
     (", ExportTableName);
  foreach(string attribName in changedAttributes)
  {
  commandString = commandString + attribName + ",";
  }
  commandString = commandString.Substring(0, commandString.Length-1); 
   // Remove last comma.
  commandString = commandString + ") VALUES (";
 
  foreach(string attribName in changedAttributes)
  {
  string val = "";
  Attrib attr = cs[attribName]; 
  if(attr.IsPresent)
  {
  switch(attr.DataType)
  {
  case AttributeType.String:
  val = "'" + EscapeStringForExport(attr.StringValue) + "'";
  break;
  case AttributeType.Integer:
  val = System.Convert.ToString(attr.IntegerValue, 10);   
  break;
  case AttributeType.Binary: // assuming GUID value (e.g. Anchor)
  val = "'" + attr.Value.ToString() + "'";  
  break;
  default:
  throw new UnexpectedDataException(String.Format("Unknown data 
        type for export add. Attr: {0} Type: {1}" + attribName, 
        attr.DataType.ToString())); 
  }
  }
  else
  {
  val = "NULL";
  }

  commandString = commandString + val + ",";
  }
  commandString = commandString.Substring(0, commandString.Length-1); 
   // remove last comma
  commandString = commandString + ")";
  //---------------------------------------------------------------
  // Build the SQL Insert Query.
  //---------------------------------------------------------------

  //---------------------------------------------------------------
  // Execute the SQL Insert Query.
  //---------------------------------------------------------------
  OleDbCommand myCommand = new OleDbCommand(commandString, 
    ExportConnection);
  try { myCommand.ExecuteNonQuery(); }
  catch { throw; } // need better exception to report back the command 
    sent to SQL
  } // insert entry

  private void DeleteEntry(CSEntry cs)
  {
  string anchor = GetAnchorAttributeName(cs);
  string anchorValue = cs[anchor].Value.ToString();
  if(EscapeAnchorAttribute(cs))
  {
  anchorValue = String.Format("'{0}'", anchorValue); 
  }

  // Build the SQL Delete Query.
  string commandString = String.Format("DELETE FROM {0} 
     WHERE {1}={2}", ExportTableName, anchor, anchorValue);

  // Execute the SQL Delete Query.
  OleDbCommand myCommand = new OleDbCommand(commandString, 
     ExportConnection);
  try { myCommand.ExecuteNonQuery(); }
  catch { throw; } // need better exception to report back the 
     command sent to SQL
  } 
  // DeleteEntry

  public void EndExport()
  {
  ExportConnection.Close();
  }
  }
}

The example assumes that the call-based data source consumes an XML file in the following format:

- <export-ma server="FABRIKAM" export-date="2004-07-12 20:20:56.033">
- <!-- WARNING>
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!
!! The contents of this file should not be edited.
!! Any modifications to this file may result in errors during import.
!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
</WARNING
-->
- <ma-data>
  <format-version>1</format-version> 
  <id>{9DCAE092-8BF0-4483-A943-BBF1BD0C2CE7}</id> 
  <name>OLEDB Database MA</name> 
  <category>Extensible</category> 
  <subtype /> 
  <ma-listname /> 
  <ma-companyname /> 
  <creation-time>2004-07-12 19:11:08.183</creation-time> 
  <last-modification-time>2004-07-12 20:17:57.336_
  </last-modification-time> 
  <version>4</version> 
  <password-sync-allowed>0</password-sync-allowed> 
- <schema>
  - <dsml:dsml xmlns:dsml="http://www.fabrikam.com/DSML"_
    xmlns:ms-dsml="http://www.fabrikam.com/MMS/DSML">
    - <dsml:directory-schema _
       ms-dsml:no-objectclass-validation="true">
      - <dsml:class id="person" type="structural">
         <dsml:name>person</dsml:name> 
         <dsml:attribute ref="#accountType" required="false" /> 
         <dsml:attribute ref="#company" required="false" /> 
         <dsml:attribute ref="#costCenter" required="false" /> 
         <dsml:attribute ref="#department" required="false" /> 
         <dsml:attribute ref="#displayName" required="false" /> 
         <dsml:attribute ref="#domainName" required="false" /> 
         <dsml:attribute ref="#employeeID" required="true" /> 
         <dsml:attribute ref="#firstname" required="false" /> 
         <dsml:attribute ref="#identityGuid" required="false" /> 
         <dsml:attribute ref="#lastname" required="false" /> 
         <dsml:attribute ref="#logonName" required="false" /> 
         <dsml:attribute ref="#mail" required="false" /> 
         <dsml:attribute ref="#mailNickname" required="false" /> 
         <dsml:attribute ref="#managerEmployeeID" required="false" /> 
         <dsml:attribute ref="#objectType" required="false" /> 
         <dsml:attribute ref="#phoneNumber" required="false" /> 
         <dsml:attribute ref="#samAccountName" required="false" /> 
         <dsml:attribute ref="#title" required="false" /> 
         <dsml:attribute ref="#pager" required="false" /> 
         <dsml:attribute ref="#mobile" required="false" /> 
         <dsml:attribute ref="#export_password" required="false" /> 
       </dsml:class>
    - <dsml:attribute-type id="accountType" single-value="true">
        <dsml:name>accountType</dsml:name> 
        <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
      </dsml:attribute-type>
    - <dsml:attribute-type id="company" single-value="true">
       <dsml:name>company</dsml:name> 
       <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
      </dsml:attribute-type>
    - <dsml:attribute-type id="costCenter" single-value="true">
       <dsml:name>costCenter</dsml:name> 
       <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
      </dsml:attribute-type>
    - <dsml:attribute-type id="department" single-value="true">
       <dsml:name>department</dsml:name> 
       <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
      </dsml:attribute-type>
    - <dsml:attribute-type id="displayName" single-value="true">
       <dsml:name>displayName</dsml:name> 
       <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
      </dsml:attribute-type>
    - <dsml:attribute-type id="domainName" single-value="true">
         <dsml:name>domainName</dsml:name> 
         <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
      </dsml:attribute-type>
    - <dsml:attribute-type id="employeeID" single-value="true"_
      ms-dsml:immutable="true">
         <dsml:name>employeeID</dsml:name> 
         <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
      </dsml:attribute-type>
    - <dsml:attribute-type id="firstname" single-value="true">
         <dsml:name>firstname</dsml:name> 
         <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
      </dsml:attribute-type>
   - <dsml:attribute-type id="identityGuid" single-value="true">
         <dsml:name>identityGuid</dsml:name> 
         <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
     </dsml:attribute-type>
   - <dsml:attribute-type id="lastname" single-value="true">
         <dsml:name>lastname</dsml:name> 
         <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
     </dsml:attribute-type>
   - <dsml:attribute-type id="logonName" single-value="true">
     <dsml:name>logonName</dsml:name> 
     <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
     </dsml:attribute-type>
   - <dsml:attribute-type id="mail" single-value="true">
     <dsml:name>mail</dsml:name> 
     <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
     </dsml:attribute-type>
   - <dsml:attribute-type id="mailNickname" single-value="true">
     <dsml:name>mailNickname</dsml:name> 
     <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
     </dsml:attribute-type>
   - <dsml:attribute-type id="managerEmployeeID" _
     single-value="true">
     <dsml:name>managerEmployeeID</dsml:name> 
     <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
     </dsml:attribute-type>
   - <dsml:attribute-type id="objectType" single-value="true">
     <dsml:name>objectType</dsml:name> 
     <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
     </dsml:attribute-type>
   - <dsml:attribute-type id="phoneNumber" single-value="true">
     <dsml:name>phoneNumber</dsml:name> 
     <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
     </dsml:attribute-type>
   - <dsml:attribute-type id="samAccountName" single-value="true">
     <dsml:name>samAccountName</dsml:name> 
     <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
     </dsml:attribute-type>
   - <dsml:attribute-type id="title" single-value="true">
     <dsml:name>title</dsml:name> 
     <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
     </dsml:attribute-type>
   - <dsml:attribute-type id="pager" single-value="true">
     <dsml:name>pager</dsml:name> 
     <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
     </dsml:attribute-type>
   - <dsml:attribute-type id="mobile" single-value="true">
     <dsml:name>mobile</dsml:name> 
     <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
     </dsml:attribute-type>
   - <dsml:attribute-type id="export_password" _
     single-value="true" ms-dsml:encrypted="true" _
     ms-dsml:export-only="true">
     <dsml:name>export_password</dsml:name> 
     <dsml:syntax>1.3.6.1.4.1.1466.115.121.1.15</dsml:syntax> 
     </dsml:attribute-type>
    </dsml:directory-schema>
   </dsml:dsml>
  </schema>
- <attribute-inclusion>
   <attribute>accountType</attribute> 
   <attribute>company</attribute> 
   <attribute>costCenter</attribute> 
   <attribute>department</attribute> 
   <attribute>displayName</attribute> 
   <attribute>domainName</attribute> 
   <attribute>employeeID</attribute> 
   <attribute>firstname</attribute> 
   <attribute>identityGuid</attribute> 
   <attribute>lastname</attribute> 
   <attribute>logonName</attribute> 
   <attribute>mail</attribute> 
   <attribute>mailNickname</attribute> 
   <attribute>managerEmployeeID</attribute> 
   <attribute>objectType</attribute> 
   <attribute>phoneNumber</attribute> 
   <attribute>samAccountName</attribute> 
   <attribute>title</attribute> 
   <attribute>pager</attribute> 
   <attribute>mobile</attribute> 
   <attribute>export_password</attribute> 
  </attribute-inclusion>
  <stay-disconnector /> 
- <join>
 - <join-profile cd-object-type="person">
  - <join-criterion id="{45B13AEB-A596-4AFC-B0CD-D9465D835D76}">
   - <search mv-object-type="person">
    - <attribute-mapping mv-attribute="employeeID">
     - <direct-mapping>
        <src-attribute>employeeID</src-attribute> 
       </direct-mapping>
      </attribute-mapping>
     </search>
   - <resolution type="none">
      <script-context /> 
     </resolution>
    </join-criterion>
   </join-profile>
  </join>
- <projection>
 - <class-mapping type="declared" id="_
   {7D985F8D-0FF3-430B-B207-E77F01844AE0}" cd-object-type="person">
    <mv-object-type>person</mv-object-type> 
   </class-mapping>
  </projection>
  <export-attribute-flow /> 
- <provisioning-cleanup type="declared">
   <action>make-normal-disconnector</action> 
  </provisioning-cleanup>
  <extension /> 
- <controller-configuration>
   <application-protection>high</application-protection> 
  </controller-configuration>
  <description /> 
- <ma-ui-settings>
  - <account-joiner-queries>
   - <attributes>
    - <cs>
       <attribute name="employeeID" header="employeeID" size="100" /> 
       <attribute name="accountType" header="accountType" size="100" /> 
       <attribute name="company" header="company" size="100" /> 
      </cs>
     <mv/> 
    </attributes>
    <filters max_mv_search_results="" /> 
   </account-joiner-queries>
  </ma-ui-settings>
- <private-configuration>
 - <MAConfig>
  - <ui-data>
   - <xmlwizard>
    - <properties>
      <sample_file>C:\import.csv</sample_file> 
      <code_page_description>Unicode</code_page_description> 
     </properties>
   - <partitions>
    - <partition cd_name="default" guid="_
      {483FBBF8-E722-4DB4-9D2F-1CC58D9CB3E6}" version="3">
       <object_class>person</object_class> 
      </partition>
     </partitions>
   - <primary_class_mappings>
    - <mapping object_class="person" primary_class="person"_
      user_define="-1">
       <attribute>accountType</attribute> 
       <attribute>company</attribute> 
       <attribute>costCenter</attribute> 
       <attribute>department</attribute> 
       <attribute>displayName</attribute> 
       <attribute>domainName</attribute> 
       <attribute>employeeID</attribute> 
       <attribute>firstname</attribute> 
       <attribute>identityGuid</attribute> 
       <attribute>lastname</attribute> 
       <attribute>logonName</attribute> 
       <attribute>mail</attribute> 
       <attribute>mailNickname</attribute> 
       <attribute>managerEmployeeID</attribute> 
       <attribute>objectType</attribute> 
       <attribute>phoneNumber</attribute> 
       <attribute>samAccountName</attribute> 
       <attribute>title</attribute> 
       <attribute>pager</attribute> 
       <attribute>mobile</attribute> 
      </mapping>
     </primary_class_mappings>
   - <object_classes>
    - <object_class cd_name="person" selected="-1" _
      user_define="-1" configured="-1" anchor="" dn_as_anchor="0">
       <attribute mandatory="0">accountType</attribute> 
       <attribute mandatory="0">company</attribute> 
       <attribute mandatory="0">costCenter</attribute> 
       <attribute mandatory="0">department</attribute> 
       <attribute mandatory="0">displayName</attribute> 
       <attribute mandatory="0">domainName</attribute> 
       <attribute mandatory="-1">employeeID</attribute
       <attribute mandatory="0">firstname</attribute> 
       <attribute mandatory="0">identityGuid</attribute> 
       <attribute mandatory="0">lastname</attribute> 
       <attribute mandatory="0">logonName</attribute> 
       <attribute mandatory="0">mail</attribute> 
       <attribute mandatory="0">mailNickname</attribute> 
       <attribute mandatory="0">managerEmployeeID</attribute> 
       <attribute mandatory="0">objectType</attribute> 
       <attribute mandatory="0">phoneNumber</attribute> 
       <attribute mandatory="0">samAccountName</attribute> 
       <attribute mandatory="0">title</attribute> 
       <attribute mandatory="0">pager</attribute> 
       <attribute mandatory="0">mobile</attribute> 
      </object_class>
     </object_classes>
   - <attributes>
      <attribute cd_name="accountType" binary="0" sample_data="53"_
      multi_valued="0" file_reference="0" selected="-1" _
      type="String" lower_bound="" upper_bound="" user_define="0" /> 
      <attribute cd_name="company" binary="0" _
      sample_data="CONTOSO" multi_valued="0" file_reference="0" _
      selected="-1" type="String" lower_bound="" upper_bound="" _
      user_define="0" /> 
      <attribute cd_name="costCenter" binary="0" sample_data="90622"_
      multi_valued="0" file_reference="0" selected="-1" _
      type="String" lower_bound="" upper_bound="" user_define="0" /> 
      <attribute cd_name="department" binary="0" _
      sample_data="US-SAP Analysis & Support" multi_valued="0" _
      file_reference="0" selected="-1" type="String" lower_bound="_
      " upper_bound="" user_define="0" /> 
      <attribute cd_name="displayName" binary="0" _
      sample_data=" (US-SAP Analysis & Support)"_
      multi_valued="0" file_reference="0" selected="-1" type="String"_
      lower_bound="" upper_bound="" user_define="0" /> 
      <attribute cd_name="domainName" binary="0" _
      sample_data="DomainName" multi_valued="0" file_reference="0" _
      selected="-1" type="String" lower_bound="" upper_bound="" _
      user_define="0" /> 
      <attribute cd_name="employeeID" binary="0" _
      sample_data="216959" multi_valued="0" file_reference="0" _
      selected="-1" type="String" lower_bound="" upper_bound="" _
      user_define="0" /> 
      <attribute cd_name="firstname" binary="0" _
      sample_data="Wright" multi_valued="0" file_reference="0" _
      selected="-1" type="String" lower_bound="" upper_bound="_
      " user_define="0" /> 
      <attribute cd_name="identityGuid" binary="0" _
      sample_data="{371df4cd-ac02-4e82-82cf-00eebcf31d38}" _
      multi_valued="0" file_reference="0" selected="-1" _
      type="String" lower_bound="" upper_bound="" user_define="0" /> 
      <attribute cd_name="lastname" binary="0" _
      sample_data="Steven 123" multi_valued="0" file_reference="0"_
      selected="-1" type="String" lower_bound="" upper_bound="_
      " user_define="0" /> 
      <attribute cd_name="logonName" binary="0" _
      sample_data="DomainName\t-steven" multi_valued="0" _
      file_reference="0" selected="-1" type="String" _
      lower_bound="" upper_bound="" user_define="0" /> 
      <attribute cd_name="mail" binary="0" _
      sample_data="t-steven@contoso.com" multi_valued="0" _
      file_reference="0" selected="-1" type="String" lower_bound="_
      " upper_bound="" user_define="0" /> 
      <attribute cd_name="mailNickname" binary="0" _
      sample_data="t-steven" multi_valued="0" file_reference="0"_
      selected="-1" type="String" lower_bound="" upper_bound="_
      " user_define="0" /> 
      <attribute cd_name="managerEmployeeID" binary="0" _
      sample_data="114635" multi_valued="0" file_reference="0" _
      selected="-1" type="String" lower_bound="" upper_bound="_
      " user_define="0" /> 
      <attribute cd_name="objectType" binary="0" _
      sample_data="MSPerson" multi_valued="0" file_reference="0" _
      selected="-1" type="String" lower_bound="" upper_bound="_
      " user_define="0" /> 
      <attribute cd_name="phoneNumber" binary="0" _
      sample_data="+1 (555) 5550123 X50123" multi_valued="0" _
      file_reference="0" selected="-1" type="String" _
      lower_bound="" upper_bound="" user_define="0" /> 
      <attribute cd_name="samAccountName" binary="0" _
      sample_data="t-steven" multi_valued="0" file_reference="0"_
      selected="-1" type="String" lower_bound="" upper_bound="_
      " user_define="0" /> 
      <attribute cd_name="title" binary="0" _
      sample_data="WINTER PROGRAM MANAGER INTERN" multi_valued="0"_
      file_reference="0" selected="-1" type="String" lower_bound="_
      " upper_bound="" user_define="0" /> 
      <attribute cd_name="pager" binary="0" _
      sample_data="555-555-0196" multi_valued="0" file_reference="0"_
      selected="-1" type="String" lower_bound="" upper_bound="_
      " user_define="0" /> 
      <attribute cd_name="mobile" binary="0" _
      sample_data="555-555-0145" multi_valued="0" _
      file_reference="0" selected="-1" type="String" _
      lower_bound="" upper_bound="" user_define="0" /> 
     </attributes>
    </xmlwizard>
   </ui-data>
- <importing>
 - <dn>
    <attribute>employeeID</attribute> 
   </dn>
- <anchor>
   <attribute>employeeID</attribute> 
  </anchor>
  <per-class-settings /> 
  <default_object_class>person</default_object_class> 
 </importing>
 <exporting /> 
 <ldap-dn>0</ldap-dn> 
- <attribute_value_pair_format>
   <code_page>1200</code_page> 
  </attribute_value_pair_format>
- <primary_class_mappings>
 - <mapping>
    <primary_class>person</primary_class> 
    <oc-value>person</oc-value> 
   </mapping>
  </primary_class_mappings>
- <password-extension-config>
   <password-extension-enabled>0</password-extension-enabled> 
   <dll /> 
  <password-set-enabled /> 
  <password-change-enabled /> 
- <connection-info>
   <connect-to /> 
   <user /> 
  </connection-info>
  <timeout /> 
  </password-extension-config>
- <extension-config>
   <filename>OLEDB Database MAExtension.dll</filename> 
   <export-mode>call-based</export-mode> 
   <import-enabled>1</import-enabled> 
   <export-enabled>1</export-enabled> 
- <connection-info>
   <connect-to>localhost</connect-to> 
   <user>sa</user> 
  </connection-info>
- <attributes>
   <attribute name="Database">MIISSA</attribute> 
   <attribute name="Table">IdentityStore</attribute> 
   <attribute name="SQLWhereClause">CostCenter in ('90622')_
   </attribute> 
   <attribute name="Provider">SQLOLEDB</attribute> 
   <attribute name="Security">SSPI</attribute> 
   <attribute name="Timeout">30</attribute> 
  </attributes>
  </extension-config>
  <file-type>AVP</file-type> 
 </MAConfig>
 </private-configuration>
- <ma-partition-data>
- <partition>
   <id>{483FBBF8-E722-4DB4-9D2F-1CC58D9CB3E6}</id> 
   <name>default</name> 
   <creation-time>2004-07-12 19:11:08.183</creation-time> 
   <last-modification-time>2004-07-12 20:17:57.327_
   </last-modification-time> 
   <version>4</version> 
   <selected>1</selected> 
 - <filter>
  - <object-classes>
     <object-class>person</object-class> 
    </object-classes>
 - <containers>
    <exclusions /> 
  - <inclusions>
     <inclusion /> 
    </inclusions>
   </containers>
  </filter>
  <allowed-operations>31</allowed-operations> 
- <current>
   <batch-number>1</batch-number> 
   <sequence-number>0</sequence-number> 
  </current>
  <last-successful-batch>0</last-successful-batch> 
- <filter-hints> 
 - <object-classes>
  - <object-class>
     <name>person</name> 
   - <hierarchy>
      <object-class>person</object-class> 
     </hierarchy>
     <included>1</included> 
    </object-class>
   </object-classes>
  </filter-hints>
 </partition>
</ma-partition-data>
- <ma-run-data>
- <run-configuration>
   <id>{1D98F06C-094E-4236-9F0F-A5981BCE687D}</id> 
   <name>Export</name> 
   <creation-time>2004-07-12 20:14:01.940</creation-time> 
   <version>1</version> 
   <last-modification-time>2004-07-12 20:14:01.940_
   </last-modification-time> 
- <configuration>
- <step>
   <step-type type="export" /> 
   <threshold /> 
   <partition>{483FBBF8-E722-4DB4-9D2F-1CC58D9CB3E6}</partition> 
- <custom-data>
 - <run-config>
    <input-file /> 
    <timeout>0</timeout> 
   </run-config>
  </custom-data>
 </step>
</configuration>
</run-configuration>
- <run-configuration>
   <id>{74374014-3FDB-44EC-A194-00FF139AB44F}</id> 
   <name>Export+FullImport+DeltaSync</name> 
   <creation-time>2004-07-12 20:14:01.940</creation-time> 
   <version>1</version> 
   <last-modification-time>2004-07-12 20:14:01.940_
   </last-modification-time> 
 - <configuration>
  - <step>
    <step-type type="export" /> 
    <threshold /> 
    <partition>{483FBBF8-E722-4DB4-9D2F-1CC58D9CB3E6}</partition> 
  - <custom-data>
   - <run-config>
      <input-file /> 
      <timeout>0</timeout> 
     </run-config>
    </custom-data>
   </step>
 - <step>
    <step-type type="full-import" /> 
    <threshold /> 
    <partition>{483FBBF8-E722-4DB4-9D2F-1CC58D9CB3E6}</partition> 
  - <custom-data>
   - <run-config>
      <input-file>import.avp.txt</input-file> 
      <delete-file-after-use>0</delete-file-after-use> 
      <timeout>0</timeout> 
     </run-config>
    </custom-data>
   </step>
  </configuration>
 </run-configuration>
- <run-configuration>
   <id>{18B8482E-BE7A-456B-B084-23DB27D14027}</id> 
   <name>FullImport+DeltaSync</name> 
   <creation-time>2004-07-12 20:14:01.930</creation-time> 
   <version>2</version> 
   <last-modification-time>2004-07-12 20:14:32.903_
   </last-modification-time> 
 - <configuration>
  - <step>
     <step-type type="full-import" /> 
     <threshold /> 
     <partition>{483FBBF8-E722-4DB4-9D2F-1CC58D9CB3E6}</partition> 
   - <custom-data>
    - <run-config>
       <input-file>import.avp.txt</input-file> 
       <delete-file-after-use>0</delete-file-after-use> 
       <timeout>0</timeout> 
      </run-config>
     </custom-data>
    </step>
   </configuration>
  </run-configuration>
 </ma-run-data>
 <capabilities-mask>7b801</capabilities-mask> 
 <export-type>3</export-type> 
- <dn-construction>
   <attribute>employeeID</attribute> 
  </dn-construction>
- <password-sync>
   <maximum-retry-count>10</maximum-retry-count> 
   <retry-interval>60</retry-interval> 
   <allow-low-security>0</allow-low-security> 
  </password-sync>
  </ma-data>
- <mv-data>
 - <import-attribute-flow>
  - <import-flow-set mv-object-type="person">
   - <import-flows mv-attribute="displayName" type="ranked">
    - <import-flow src-ma="{9DCAE092-8BF0-4483-A943-BBF1BD0C2CE7}_
    " cd-object-type="person" id="_
    {B1F95D79-E7EE-4983-A52C-EFE4DD2EA2B6}">
     - <direct-mapping>
        <src-attribute>displayName</src-attribute> 
       </direct-mapping>
      </import-flow>
    - <import-flow src-ma="{54686980-A9D6-463D-859F-32AFAC045B1A}_
      " cd-object-type="person" id="_
      {792C99AA-0ED3-4F48-9932-91327D92ADED}">
     - <direct-mapping>
        <src-attribute>displayName</src-attribute> 
       </direct-mapping>
      </import-flow>
     </import-flows>
   - <import-flows mv-attribute="givenName" type="ranked">
    - <import-flow src-ma="{9DCAE092-8BF0-4483-A943-BBF1BD0C2CE7}_
      " cd-object-type="person" id="_
      {F20E677D-B5E7-4EC4-A30E-E8E56CF01DD1}">
     - <direct-mapping>
        <src-attribute>firstname</src-attribute> 
       </direct-mapping>
      </import-flow>
   - <import-flow src-ma="{54686980-A9D6-463D-859F-32AFAC045B1A}" _
   cd-object-type="person" id="_
   {8E7C124A-D0E6-4B18-A9A3-EE20DE019250}">
    - <direct-mapping>
       <src-attribute>first</src-attribute> 
      </direct-mapping>
     </import-flow>
    </import-flows>
 - <import-flows mv-attribute="sn" type="ranked">
  - <import-flow src-ma="{9DCAE092-8BF0-4483-A943-BBF1BD0C2CE7}" _
    cd-object-type="person" id="_
    {662F7FFC-AC3B-4D2F-BBC2-7098B6E07DDD}">
   - <direct-mapping>
      <src-attribute>lastname</src-attribute> 
     </direct-mapping>
    </import-flow>
   </import-flows>
 - <import-flows mv-attribute="company" type="ranked">
  - <import-flow src-ma="{9DCAE092-8BF0-4483-A943-BBF1BD0C2CE7}" _
    cd-object-type="person" id="_
    {EAF1F4B2-AD8F-4A1C-8526-74B8655F0F8E}">
   - <direct-mapping>
      <src-attribute>company</src-attribute> 
     </direct-mapping>
    </import-flow>
 - <import-flow src-ma="{54686980-A9D6-463D-859F-32AFAC045B1A}" _
    cd-object-type="person" id="_
    {5990AB3C-0FED-4EA0-809C-944A71DBBFB5}">
 - <direct-mapping>
    <src-attribute>company</src-attribute> 
   </direct-mapping>
  </import-flow>
 </import-flows>
- <import-flows mv-attribute="mailNickname" type="ranked">
- <import-flow src-ma="{9DCAE092-8BF0-4483-A943-BBF1BD0C2CE7}" _
  cd-object-type="person" id="_
  {F31E1BF1-2815-4097-90F9-43027A2BD47F}">
- <direct-mapping>
  <src-attribute>samAccountName</src-attribute> 
  </direct-mapping>
  </import-flow>
- <import-flow src-ma="{9DCAE092-8BF0-4483-A943-BBF1BD0C2CE7}" _
  cd-object-type="person" id="_
  {C4908202-6AE6-44FB-B91E-8627F2846A0B}">
- <direct-mapping>
  <src-attribute>mailNickname</src-attribute> 
  </direct-mapping>
  </import-flow>
- <import-flow src-ma="{54686980-A9D6-463D-859F-32AFAC045B1A}" _
  cd-object-type="person" id="_
  {350D4BA7-AFC2-4610-BC76-FAD46C1AFE72}">
- <direct-mapping>
  <src-attribute>samAccountName</src-attribute> 
  </direct-mapping>
  </import-flow>
  </import-flows>
- <import-flows mv-attribute="department" type="ranked">
- <import-flow src-ma="{9DCAE092-8BF0-4483-A943-BBF1BD0C2CE7}" _
  cd-object-type="person" id="_
  {AE8AED48-ABA5-4D13-BCF6-7F087341448B}">
- <direct-mapping>
  <src-attribute>department</src-attribute> 
  </direct-mapping>
  </import-flow>
- <import-flow src-ma="{54686980-A9D6-463D-859F-32AFAC045B1A}" _
  cd-object-type="person" id="_
  {5C7CE82C-9402-4CF3-A05E-CFCD1B0A9F00}">
- <direct-mapping>
  <src-attribute>department</src-attribute> 
  </direct-mapping>
  </import-flow>
  </import-flows>
- <import-flows mv-attribute="employeeType" type="ranked">
- <import-flow src-ma="{9DCAE092-8BF0-4483-A943-BBF1BD0C2CE7}" _
  cd-object-type="person" id="_
  {C763C66B-3E19-491E-AD41-B8FAF6F1ED69}">
- <direct-mapping>
  <src-attribute>accountType</src-attribute> 
  </direct-mapping>
  </import-flow>
- <import-flow src-ma="{54686980-A9D6-463D-859F-32AFAC045B1A}" _
  cd-object-type="person" id="_
  {AD0E35CC-C0F2-4DFF-9483-F324342E6EAD}">
- <scripted-mapping>
  <src-attribute>accountType</src-attribute> 
  <script-context>cd.person:accountType->mv.person:_
  employeeType</script-context> 
  </scripted-mapping>
  </import-flow>
  </import-flows>
- <import-flows mv-attribute="division" type="ranked">
- <import-flow src-ma="{9DCAE092-8BF0-4483-A943-BBF1BD0C2CE7}" _
  cd-object-type="person" id="_
  {B7EEDD5F-FB0F-4BD0-B55C-BF2E6F6018B6}">
- <direct-mapping>
  <src-attribute>costCenter</src-attribute> 
  </direct-mapping>
  </import-flow>
- <import-flow src-ma="{54686980-A9D6-463D-859F-32AFAC045B1A}" _
  cd-object-type="person" id="{5A324740-68F4-46D6-8C22-09F9C3D34D77}">
- <direct-mapping>
  <src-attribute>costCenter</src-attribute> 
  </direct-mapping>
  </import-flow>
  </import-flows>
- <import-flows mv-attribute="employeeID" type="ranked">
- <import-flow src-ma="{9DCAE092-8BF0-4483-A943-BBF1BD0C2CE7}" cd-object-type="person" id="{6BF349C1-A81E-4672-89A0-E585027DDE59}">
- <direct-mapping>
  <src-attribute>employeeID</src-attribute> 
  </direct-mapping>
  </import-flow>
- <import-flow src-ma="{54686980-A9D6-463D-859F-32AFAC045B1A}" cd-object-type="person" id="{DB2559CA-52C6-4448-BE31-4FFF84F9B27A}">
- <direct-mapping>
  <src-attribute>employeeID</src-attribute> 
  </direct-mapping>
  </import-flow>
  </import-flows>
- <import-flows mv-attribute="mail" type="ranked">
- <import-flow src-ma="{9DCAE092-8BF0-4483-A943-BBF1BD0C2CE7}"_
  cd-object-type="person" id="_
  {38642D45-5F34-49F7-B94D-1CA56DBB4146}">
- <direct-mapping>
  <src-attribute>mail</src-attribute> 
  </direct-mapping>
  </import-flow>
  </import-flows>
- <import-flows mv-attribute="mobile" type="ranked">
- <import-flow src-ma="{9DCAE092-8BF0-4483-A943-BBF1BD0C2CE7}"_
   cd-object-type="person" id="_
  {43EFC2E5-823D-4A21-BE50-B2C22C211334}">
- <direct-mapping>
  <src-attribute>mobile</src-attribute> 
  </direct-mapping>
  </import-flow>
  </import-flows>
- <import-flows mv-attribute="pager" type="ranked">
- <import-flow src-ma="{9DCAE092-8BF0-4483-A943-BBF1BD0C2CE7}"_
   cd-object-type="person" id="_
   {84C099ED-0414-48EB-92E1-E62C9D545429}">
- <direct-mapping>
  <src-attribute>pager</src-attribute> 
  </direct-mapping>
  </import-flow>
  </import-flows>
- <import-flows mv-attribute="telephoneNumber" type="ranked">
- <import-flow src-ma="{9DCAE092-8BF0-4483-A943-BBF1BD0C2CE7}" _
  cd-object-type="person" id="{11C5EA30-A173-4A5B-814E-BF4266AC1F90}">
- <direct-mapping>
  <src-attribute>phoneNumber</src-attribute> 
  </direct-mapping>
  </import-flow>
  </import-flows>
- <import-flows mv-attribute="title" type="ranked">
- <import-flow src-ma="{9DCAE092-8BF0-4483-A943-BBF1BD0C2CE7}"_
   cd-object-type="person" id="_
   {DAB2FB28-E7C6-477E-B083-9F4DC989A390}">
- <direct-mapping>
  <src-attribute>title</src-attribute> 
  </direct-mapping>
  </import-flow>
  </import-flows>
  </import-flow-set>
- <per-ma-options>
- <ma-options ma-id="{54686980-A9D6-463D-859F-32AFAC045B1A}">
  <enable-recall>true</enable-recall> 
  </ma-options>
- <ma-options ma-id="{1F41DB0A-8E02-4BF8-B77A-81AF5C6FB2F6}">
  <enable-recall>true</enable-recall> 
  </ma-options>
- <ma-options ma-id="{9DCAE092-8BF0-4483-A943-BBF1BD0C2CE7}">
  <enable-recall>true</enable-recall> 
  </ma-options>
  </per-ma-options>
  </import-attribute-flow>
  </mv-data>
  </export-ma>

The example then generates a comma-delimited file. The contents of this file are imported into the metaverse and then exported to a call-based data source.

See Also

Concepts

Connected Data Source Extensions for Call-Based Data Sources
Creating Connected Data Source Extensions
Testing and Debugging Connected Data Source Extensions
Connected Data Source Extensions for File-Based Data Sources