Sdílet prostřednictvím


How to: Filter Enumerated Items

This topic describes how to use a managed language to filter the items enumerated by a Sync Framework synchronization provider that synchronizes data from a custom data store.

This topic assumes a basic familiarity with C# and Microsoft .NET Framework concepts.

The examples in this topic focus on the following Sync Framework classes and members:

Understanding Item Filtering

An item filter restricts which item changes are sent by the source provider during change enumeration, such as to send only .txt files in a file folder, ignoring files of other types. Items must not change in a way that causes an existing item to move into or out of the filter. Item filters are simple to use, but the metadata used for synchronization grows in proportion to the number of items that are in the synchronization scope. If storage is a concern, custom filters are appropriate. For more information on custom filtering, see Filtering Synchronization Data.

The way that items are filtered is defined outside of Sync Framework, typically by the provider developer or a third party. The filter can be set by the synchronization application by using whatever mechanism is appropriate between the application and the provider, or it can be negotiated between the two providers. For more information on negotiating filters, see Filtering Synchronization Data.

The destination provider receives and applies changes the same was it does for a standard change batch. It requires no special action to account for the filtering.

Build Requirements

Example

The example code in this topic shows how to implement a simple item filter and how to use the metadata storage service to produce a filtered change batch. The replica in this example is a text file that stores contact information as a list of comma-separated values. The items to synchronize are the contacts that are contained in this file. The filter is defined to include only contacts that have a birth date field that is less than the value specified by the application.

Setting the Filter

The source provider implements a public method that allows the application to set a filter that defines the maximum value for the birth date field. Any contact with a value greater than this value in the birth date field will not be included in a change batch.

public void SetMaximumBirthdateFilter(DateTime maxBirthdateFilter)
{
    // Store the fact that a filter is set, and the value of the filter.
    _isFiltered = true;
    _maxBirthdateFilter = maxBirthdateFilter;
}

The synchronization application creates the source provider as the local provider and uses the SetMaximumBirthdateFilter method to specify the maximum birth date to include when enumerating changes. The application also creates the destination provider and performs synchronization.

private void SynchronizeWithItemFiltering(ContactStore localStore, ContactStore remoteStore, SyncDirectionOrder syncDir)
{
    // Create the local provider and set the item filter.
    // The filter is ignored when the provider is the destination provider.
    SyncProvider localProvider = new ContactsProviderItemFiltering(localStore);
    // Only include contacts with a birthdate before January 1, 2000.
    ((ContactsProviderItemFiltering)localProvider).SetMaximumBirthdateFilter(
        new DateTime(2000, 1, 1));

    // Create the remote provider and do not set a filter.
    SyncProvider remoteProvider = new ContactsProviderItemFiltering(remoteStore);

    // Create the synchronization orchestrator and set the providers and synchronization direction.
    SyncOrchestrator orchestrator = new SyncOrchestrator();
    orchestrator.LocalProvider = localProvider;
    orchestrator.RemoteProvider = remoteProvider;
    orchestrator.Direction = syncDir;

    string msg;
    try
    {
        // Synchronize data between the two providers.
        SyncOperationStatistics stats = orchestrator.Synchronize();

        // Display statistics for the synchronization operation.
        msg = "Synchronization succeeded!\n\n" +
            stats.DownloadChangesApplied + " download changes applied\n" +
            stats.DownloadChangesFailed + " download changes failed\n" +
            stats.UploadChangesApplied + " upload changes applied\n" +
            stats.UploadChangesFailed + " upload changes failed";
    }
    catch (Exception ex)
    {
        msg = "Synchronization failed! Here's why: \n\n" + ex.Message;
    }
    MessageBox.Show(msg, "Synchronization Results");
}

Enumerating a Filtered Change Batch

The source provider implements GetChangeBatch so that, when a filter has been specified, it uses the metadata storage service to produce a filtered change batch. This is done by creating an ItemListFilterInfo object and passing it to the GetFilteredChangeBatch method of the ReplicaMetadata object.

public override ChangeBatch GetChangeBatch(uint batchSize, SyncKnowledge destinationKnowledge, out object changeDataRetriever)
{
    // Return this object as the IChangeDataRetriever object that is called to retrieve item data.
    changeDataRetriever = this;

    // Use the metadata storage service to get a batch of changes.
    ChangeBatch retrievedBatch;
    if (_isFiltered)
    {
        // If a filter is set, get a filtered change batch from the metadata storage service.
        // The BirthdateFilterCallback method indicates whether an item passes the filter.
        ItemListFilterInfo filterInfo = new ItemListFilterInfo(IdFormats);
        retrievedBatch = _ContactStore.ContactReplicaMetadata.GetFilteredChangeBatch(batchSize, destinationKnowledge,
            filterInfo, BirthdateFilterCallback);
    }
    else
    {
        retrievedBatch = _ContactStore.ContactReplicaMetadata.GetChangeBatch(batchSize, destinationKnowledge);
    }

    return retrievedBatch;
}

To determine whether an item is included in the filter, the GetFilteredChangeBatch method takes an ItemFilterCallback delegate that is implemented by the source provider. The metadata storage service calls this delegate and uses the return value to include or exclude items from the change batch. In this example, an item is included in the change batch when the value of the birth date field is less than the specified maximum birth date.

public bool BirthdateFilterCallback(ItemMetadata itemMeta)
{
    // An item passes the filter only if its birthdate field is less than the maximum birthdate
    // specified by the filter.
    return (_ContactStore.ContactList[itemMeta.GlobalId].Birthdate < _maxBirthdateFilter);
}

Next Steps

Next, you might want to add filter negotiation to your provider so that it can communicate with the destination provider to establish which filter to use for change enumeration. For more information on how to negotiate filters, see How to: Negotiate a Filter.

You might also want to use a custom filter instead of an item filter. Custom filters require more work to implement, but are much more efficient to track and communicate, so their use keeps synchronization metadata small. For more information on custom filters, see Filtering Synchronization Data.

See Also

Concepts

Programming Common Standard Custom Provider Tasks
Filtering Synchronization Data