Using replica creation events to extend the replica creation process


Summary
Developers might want to extend the core replica creation behavior. The replication creation process can be extended by implementing a workspace extension that supports IWorkspaceReplicaEvents. By implementing this interface in an extension, custom behavior can be executed before and after any replica creation process executed on a geodatabase.
This topic describes the process using the example of a developer wanting to copy a nonversioned look-up table from the source to the target geodatabase during replica creation. Replica creation needs to be extended to cover this requirement since data involved in a replica must be versioned.
The code example in this topic can be used as a reference for developers needing to extend replica creation for any reason.


Building the workspace extension

A workspace extension can be created to extend the behavior of a geodatabase. Once created, the extension can be associated with specific geodatabases. It can also be registered on a client machine where it will be applied to any geodatabase accessed on that machine.
For more information on how to build and associate a workspace extension with a geodatabase, see Creating workspace extensions.

Extending replica creation with the workspace extension

With a workspace extension, replica creation can be extended by implementing the IWorkspaceReplicaEvents interface. This interface includes a BeforeCreateChildReplica method and an AfterCreateChildReplica method. During replica creation, these methods are called when the extension is associated with the source geodatabase. The BeforeCreateChildReplica method is called before the internal replica creation behavior has been executed. The AfterCreateChildReplica is called once the internal replica creation behavior has been completed.
Add code to the BeforeCreateChildReplica method to ensure that certain options are applied during replica creation. This method allows the replica description to be changed before it is used by the internal replica creation process. This way, the default replica creation behavior can be altered. For example, new feature classes and tables could be added to the replica, the filters could be changed, or feature classes and tables that are already set to be replicated could be removed.
The AfterCreateChildReplica method can be used to add code to augment the replica creation process with additional behavior. The code example shows how to augment replica creation by copying a nonversioned table from the source geodatabase to the target geodatabase. This can be done by adding code to the AfterCreateChildReplica method. If there is a failure during the internal replica creation process, this method will not be called and code will not have to be added to clean up the target geodatabase.
The following code example shows an implementation of the AfterCreateChildReplica method that copies a table (LookupTable) from the source geodatabase to the target geodatabase. In this code example, LookupTable is not part of the replica since it is not versioned in the source geodatabase. 
[C#]
public void AfterCreateChildReplica(String name, esriReplicaType replicaType,
    IReplicaDescription replicaDesc, IWorkspace childWorkspace)
{
    // Get the source geodatabase. Note: This is stored in a global variable in the extension.
    IWorkspace parentWorkspace = workspaceHelper.Workspace;
    IDataset parentDataset = (IDataset)parentWorkspace;
    IWorkspaceName parentWorkspaceName = (IWorkspaceName)parentDataset.FullName;

    // Add the table (LookupTable) to a Names enumerator.
    IEnumName enumName = new NamesEnumeratorClass();
    IEnumNameEdit enumNameEdit = (IEnumNameEdit)enumName;
    ITableName tableName = new TableNameClass();
    IDatasetName datasetName = (IDatasetName)tableName;
    datasetName.WorkspaceName = parentWorkspaceName;
    datasetName.Name = "LookupTable";
    IName lookupName = (IName)datasetName;
    enumNameEdit.Add(lookupName);

    // Initialize the replica description using the passed in target geodatabase.
    IReplicaDescription replicaDescription = new ReplicaDescriptionClass();
    IDataset replicaDataset = (IDataset)childWorkspace;
    IName replicaName = replicaDataset.FullName;
    IWorkspaceName replicaWorkspaceName = (IWorkspaceName)replicaName;
    replicaDescription.Init(enumName, replicaWorkspaceName, false,
        esriDataExtractionType.esriDataExtraction);

    // Set the filter for the table to all rows.
    int tableIndex = replicaDescription.FindTable(lookupName);
    IReplicaFilterDescriptionEdit replicaFilterDescEdit = 
        (IReplicaFilterDescriptionEdit)replicaDescription;
    replicaFilterDescEdit.set_RowsType(tableIndex, esriRowsType.esriRowsTypeAll);

    // Run a data extraction to copy the table to the target geodatabase.
    IDataExtraction dataExtraction = new DataExtractionClass();
    try
    {
        dataExtraction.Extract(replicaDescription, false);
    }
    catch (COMException comExc)
    {
        // Handle appropriately for your application.
        throw comExc;
    }
}
[VB.NET]
Public Sub AfterCreateChildReplica(ByVal Name As String, ByVal replicaType As esriReplicaType, _
                                   ByVal replicaDesc As IReplicaDescription, ByVal childWorkspace As IWorkspace) _
                                   Implements IWorkspaceReplicaEvents.BeforeCreateChildReplica
    
    ' Get the source geodatabase. Note: This is stored in a global variable in the extension.
    Dim parentWorkspace As IWorkspace = workspaceHelper.Workspace
    Dim parentDataset As IDataset = CType(parentWorkspace, IDataset)
    Dim parentWorkspaceName As IWorkspaceName = CType(parentDataset.FullName, IWorkspaceName)
    
    ' Add the table (LookupTable) to a Names enumerator.
    Dim enumName As IEnumName = New NamesEnumeratorClass()
    Dim enumNameEdit As IEnumNameEdit = CType(enumName, IEnumNameEdit)
    Dim tableName As ITableName = New TableNameClass()
    Dim datasetName As IDatasetName = CType(tableName, IDatasetName)
    datasetName.WorkspaceName = parentWorkspaceName
    datasetName.Name = "LookupTable"
    Dim lookupName As IName = CType(datasetName, IName)
    enumNameEdit.Add(lookupName)
    
    ' Initialize the replica description using the passed in target geodatabase.
    Dim replicaDescription As IReplicaDescription = New ReplicaDescriptionClass()
    Dim replicaDataset As IDataset = CType(childWorkspace, IDataset)
    Dim replicaName As IName = replicaDataset.FullName
    Dim replicaWorkspaceName As IWorkspaceName = CType(replicaName, IWorkspaceName)
    replicaDescription.Init(enumName, replicaWorkspaceName, False, esriDataExtractionType.esriDataExtraction)
    
    ' Set the filter for the table to all rows.
    Dim tableIndex As Integer = replicaDescription.FindTable(lookupName)
    Dim replicaFilterDescEdit As IReplicaFilterDescriptionEdit = CType(replicaDescription, IReplicaFilterDescriptionEdit)
    replicaFilterDescEdit.RowsType(tableIndex) = esriRowsType.esriRowsTypeAll
    
    ' Run a data extraction to copy the table to the target geodatabase.
    Dim dataExtraction As IDataExtraction = New DataExtractionClass()
    Try
    dataExtraction.Extract(replicaDescription, False)
    Catch comExc As COMException
    Throw comExc
    End Try
    
End Sub

Registering the extension

As previously discussed, a workspace extension can be registered with specific geodatabases or on the client machine. For example, since a specific table is copied from a source geodatabase during replica creation, the extension should be registered with the source geodatabase.

Creating the replica

Once the extension is associated with the source geodatabase, replicas created from that geodatabase execute the code to copy the LookUpTable. This ensures the presence of this table in the target geodatabase.
Any replica creation method can be used. This includes replicas created using the create replica wizard in ArcMap, the create replica and create replica from server geoprocessing tools, or replicas created with the application programming interface (API). For examples of how to create replicas with the API, see How to create a replica in a connected environment and How to create a replica in a disconnected environment.
Although the replica creation process can be extended in a disconnected environment, this particular example will not work. It requires the source and target geodatabases to be available at creation time. However, this example can be used as a starting point for building other applications.

Complete code example

The following is a complete code example of a workspace extension that implements the previously described behavior:
At a minimum, change the globally unique identifier (GUID) attribute parameter to a new value that will be unique. In addition, change the ProgID attribute parameter.
[C#]
[Guid("97CD2883-37CB-4f76-BD0F-945279C783DC")][ProgId(
    "SdkExamples.ReplicaWorkspaceExtensionCS")][ClassInterface
    (ClassInterfaceType.None)]
public class ReplicationWorkspaceExtension: IWorkspaceExtensionControl,
    IWorkspaceExtension2, IWorkspaceReplicaEvents
{
    private IWorkspaceHelper workspaceHelper = null;

    #region IWorkspaceExtensionControl members
    public void Init(IWorkspaceHelper workspaceHelper)
    {
        this.workspaceHelper = workspaceHelper;
    }

    public void Shutdown(){}
    #endregion 

    #region IWorkspaceExtension2 members
    public string Name
    {
        get
        {
            return "ReplicationWorkspaceExtension";
        }
    }

    public UID GUID
    {
        get
        {
            UIDClass uid = new UIDClass();
            uid.Value = "{97CD2883-37CB-4f76-BD0F-945279C783DC}";
            return uid;
        }
    }

    public IEnumBSTR get_PrivateDatasetNames(esriDatasetType dsType)
    {
        return null;
    }

    public IEnumBSTR DataDictionaryTableNames
    {
        get
        {
            return null;
        }
    }

    public bool OwnsDatasetType(esriDatasetType datasetType)
    {
        return false;
    }

    public IWorkspace Workspace
    {
        get
        {
            return workspaceHelper.Workspace;
        }
    }
    #endregion 

    #region IWorkspaceReplicaEvents members
    public void AfterCreateChildReplica(String name, esriReplicaType replicaType,
        IReplicaDescription replicaDesc, IWorkspace childWorkspace)
    {
        // Get the source geodatabase. Note: This is stored in a global variable in the extension.
        IWorkspace parentWorkspace = workspaceHelper.Workspace;
        IDataset parentDataset = (IDataset)parentWorkspace;
        IWorkspaceName parentWorkspaceName = (IWorkspaceName)parentDataset.FullName;

        // Add the table (LookupTable) to a Names enumerator.
        IEnumName enumName = new NamesEnumeratorClass();
        IEnumNameEdit enumNameEdit = (IEnumNameEdit)enumName;
        ITableName tableName = new TableNameClass();
        IDatasetName datasetName = (IDatasetName)tableName;
        datasetName.WorkspaceName = parentWorkspaceName;
        datasetName.Name = "LookupTable";
        IName lookupName = (IName)datasetName;
        enumNameEdit.Add(lookupName);

        // Initialize the replica description using the passed in target geodatabase.
        IReplicaDescription replicaDescription = new ReplicaDescriptionClass();
        IDataset replicaDataset = (IDataset)childWorkspace;
        IName replicaName = replicaDataset.FullName;
        IWorkspaceName replicaWorkspaceName = (IWorkspaceName)replicaName;
        replicaDescription.Init(enumName, replicaWorkspaceName, false,
            esriDataExtractionType.esriDataExtraction);

        // Set the filter for the table to all rows.
        int tableIndex = replicaDescription.FindTable(lookupName);
        IReplicaFilterDescriptionEdit replicaFilterDescEdit = 
            (IReplicaFilterDescriptionEdit)replicaDescription;
        replicaFilterDescEdit.set_RowsType(tableIndex, esriRowsType.esriRowsTypeAll);

        // Run a data extraction to copy the table to the target geodatabase.
        IDataExtraction dataExtraction = new DataExtractionClass();
        try
        {
            dataExtraction.Extract(replicaDescription, false);
        }
        catch (COMException comExc)
        {
            // Handle appropriately for your application.
            throw comExc;
        }
    }

    public void BeforeCreateChildReplica(String name, esriReplicaType replicaType,
        IReplicaDescription replicaDesc, IWorkspace childWorkspace){}
    #endregion 
}
[VB.NET]
<Guid("71300fc6-cb76-496d-b89f-cf1db2550788")> _
      <ProgId("SdkExamples.ReplicaWorkspaceExtensionVB")> _
      <ClassInterface(ClassInterfaceType.None)> _
      Public Class ReplicationWorkspaceExtension
    Implements IWorkspaceExtensionControl, IWorkspaceExtension2, IWorkspaceReplicaEvents
    
    Private workspaceHelper As IWorkspaceHelper = Nothing
    
    #Region "IWorkspaceExtensionControl members"

    Public Sub Init(ByVal wsHelper As IWorkspaceHelper) Implements IWorkspaceExtensionControl.Init
        workspaceHelper = wsHelper
    End Sub
    
    Public Sub Shutdown() Implements IWorkspaceExtensionControl.Shutdown
    End Sub

    #End Region
    
    #Region "IWorkspaceExtension2 members"
    Public ReadOnly Property DataDictionaryTableNames() As IEnumBSTR _
                                                      Implements IWorkspaceExtension.DataDictionaryTableNames, IWorkspaceExtension2.DataDictionaryTableNames
    Get
    Return Nothing
    End Get
End Property

Public ReadOnly Property GUID() As UID _
                              Implements IWorkspaceExtension.GUID, IWorkspaceExtension2.GUID
Get
Dim uid As UIDClass = New UIDClass()
uid.Value = "{71300fc6-cb76-496d-b89f-cf1db2550788}"
Return uid
End Get
End Property

Public ReadOnly Property Name() As String _
                              Implements IWorkspaceExtension.Name, IWorkspaceExtension2.Name
Get
Return "ReplicationWorkspaceExtension"
End Get
End Property

Public ReadOnly Property PrivateDatasetNames(ByVal dsType As esriDatasetType) As IEnumBSTR _
                                             Implements IWorkspaceExtension.PrivateDatasetNames, IWorkspaceExtension2.PrivateDatasetNames
Get
Return Nothing
End Get
End Property

Public Function OwnsDatasetType(ByVal datasetType As esriDatasetType) As Boolean _
                                Implements IWorkspaceExtension2.OwnsDatasetType
    Return False
End Function

Public ReadOnly Property Workspace() As IWorkspace _
                                   Implements IWorkspaceExtension2.Workspace
Get
Return workspaceHelper.Workspace
End Get
End Property

#End Region

#Region "IWorkspaceReplicaEvents members"

Public Sub AfterCreateChildReplica(ByVal Name As String, ByVal replicaType As esriReplicaType, _
                                   ByVal replicaDesc As IReplicaDescription, ByVal childWorkspace As IWorkspace) _
                                   Implements IWorkspaceReplicaEvents.BeforeCreateChildReplica
    
    ' Get the source geodatabase. Note: This is stored in a global variable in the extension.
    Dim parentWorkspace As IWorkspace = workspaceHelper.Workspace
    Dim parentDataset As IDataset = CType(parentWorkspace, IDataset)
    Dim parentWorkspaceName As IWorkspaceName = CType(parentDataset.FullName, IWorkspaceName)
    
    ' Add the table (LookupTable) to a Names enumerator.
    Dim enumName As IEnumName = New NamesEnumeratorClass()
    Dim enumNameEdit As IEnumNameEdit = CType(enumName, IEnumNameEdit)
    Dim tableName As ITableName = New TableNameClass()
    Dim datasetName As IDatasetName = CType(tableName, IDatasetName)
    datasetName.WorkspaceName = parentWorkspaceName
    datasetName.Name = "LookupTable"
    Dim lookupName As IName = CType(datasetName, IName)
    enumNameEdit.Add(lookupName)
    
    ' Initialize the replica description using the passed in target geodatabase.
    Dim replicaDescription As IReplicaDescription = New ReplicaDescriptionClass()
    Dim replicaDataset As IDataset = CType(childWorkspace, IDataset)
    Dim replicaName As IName = replicaDataset.FullName
    Dim replicaWorkspaceName As IWorkspaceName = CType(replicaName, IWorkspaceName)
    replicaDescription.Init(enumName, replicaWorkspaceName, False, esriDataExtractionType.esriDataExtraction)
    
    ' Set the filter for the table to all rows.
    Dim tableIndex As Integer = replicaDescription.FindTable(lookupName)
    Dim replicaFilterDescEdit As IReplicaFilterDescriptionEdit = CType(replicaDescription, IReplicaFilterDescriptionEdit)
    replicaFilterDescEdit.RowsType(tableIndex) = esriRowsType.esriRowsTypeAll
    
    ' Run a data extraction to copy the table to the target geodatabase.
    Dim dataExtraction As IDataExtraction = New DataExtractionClass()
    Try
    dataExtraction.Extract(replicaDescription, False)
    Catch comExc As COMException
    ' Handle appropriately for your application.
    Throw comExc
    End Try
End Sub

Public Sub BeforeCreateChildReplica(ByVal Name As String, ByVal rType As esriReplicaType, _
                                    ByVal rDescription As IReplicaDescription, ByVal childWorkspace As IWorkspace) _
                                    Implements IWorkspaceReplicaEvents.AfterCreateChildReplica
End Sub

#End Region

End Class


See Also:

How to create a replica in a connected environment
How to create a replica in a disconnected environment
Creating workspace extensions




To use the code in this topic, reference the following assemblies in your Visual Studio project. In the code files, you will need using (C#) or Imports (VB .NET) directives for the corresponding namespaces (given in parenthesis below if different from the assembly name):
Development licensing Deployment licensing
ArcGIS for Desktop Standard ArcGIS for Desktop Standard
ArcGIS for Desktop Advanced ArcGIS for Desktop Advanced
Engine Developer Kit Engine: Geodatabase Update