How to create an adapter for the TFS Integration Platform - Part VIII: IMigrationProvider
Note: This post is part of a series and you can find the rest of the parts in the series index.
The IMigrationProvider interface is the sister to IAnalysisProvider and handles writing to your system. As with IAnalysisProvider, it includes some methods you can ignore.
InitializeServices
As with IAnalysisProvider, the InitializeServices method is what is called first and is used for all setup. In my implementation, I do a lot of setup for SharePoint, which may not apply to other implementations. One thing you must do, however, is register your item serializer with the platform as follows:
changeGroupService.RegisterDefaultSourceSerializer(new SharePointVCMigrationItemSerializer());
ProcessChangeGroup
The ProcessChangeGroup method is the most important method of IMigrationProvider, as it is called to perform the write operation. You are provided a ChangeGroup, and the Actions property of that ChangeGroup contains each file, folder, or item you need to write, update, or delete in your system. The ProcessChangeGroup method needs to return a log of what has happened so that the platform knows all actions were performed and can correctly tie up item unique IDs in your system with those in the other system. The log is done using a ConversionResult:
ConversionResult conversionResult = new ConversionResult(configurationService.MigrationPeer, configurationService.SourceId);
Each action has an Action, which tells you what to do with the item—whether to update, add, or delete it. Each action also has an ItemTypeReferenceName, which specifies its type. For WIT (work items), this isn’t critical, but for VC (version control), it’s very important, as it could be a concrete file, folder, or a theoretical item like a branch or merge instruction.
You need to loop over all actions and perform the correct operation based on the action and type:
foreach (MigrationAction action in changeGroup.Actions)
{
if (action.Action == WellKnownChangeActionId.Add || action.Action == WellKnownChangeActionId.Edit)
{
if (action.ItemTypeReferenceName == WellKnownContentType.VersionControlledFile.ReferenceName)
{
After completing your action, you must add the details to the conversion result log. My two adapters handle this differently, but the key part is ensuring the platform knows how to link your item in the future (e.g., for deletes or updates). Here’s how I did it:
conversionResult.ItemConversionHistory.Add(new ItemConversionHistory(sourceSystemId, string.Empty, newSharePointId.ToString(), string.Empty));
Items and VC
With the VC adapter, you request the actual file by using the Download method on the source item and providing a path.
Power Tip: In my implementation, I used
Path.GetTempFileName()from the .NET framework to create a temporary file, but this automatically creates an empty file—which the platform doesn’t like. I had to delete it first and then callDownload.Power Tip: For folder creation or deletes, use the
Pathproperty of the action to get the folder name.
Items and WIT
Work item tracking (WIT) is simpler when it comes to writing, as you don’t need to worry about paths or files—just XML parsing. All item information is provided in the MigrationActionDescription property of the action, and you’ll need to parse it into an item. Since the platform handles field name mapping, this is straightforward. Here’s the small method I used to build a field list:
private static Dictionary<string, object> BuildFieldList(IMigrationAction action)
{
Dictionary<string, object> fields = new Dictionary<string, object>();
XmlNodeList columns = action.MigrationActionDescription.SelectNodes("/WorkItemChanges/Columns/Column");
foreach (XmlNode columnData in columns)
{
string fieldValue = columnData.FirstChild.InnerText;
string fieldName = columnData.Attributes["ReferenceName"].Value;
if (!string.IsNullOrEmpty(fieldName))
{
fields.Add(fieldName, fieldValue);
}
}
return fields;
}
Item ID
The platform also handles item ID mapping, so if you need to know what item to update or delete, check the MigrationActionDescription. This method works regardless of your system:
private string GetSharePointID(IMigrationAction action)
{
TraceManager.TraceInformation("WSSWIT:MP:GetSharePointID");
XmlNode workItemChangesNode = action.MigrationActionDescription.SelectSingleNode("/WorkItemChanges");
string value = string.Empty;
if (workItemChangesNode.Attributes["TargetWorkItemID"] == null)
{
TraceManager.TraceInformation("WSSWIT:MP:GetSharePointID: Cannot find work item ID. XML is: {0}", workItemChangesNode.OuterXml);
}
else
{
value = workItemChangesNode.Attributes["TargetWorkItemID"].Value;
TraceManager.TraceInformation("WSSWIT:MP:GetSharePointID: Value {0}", value);
}
return value;
}