Skip to main content

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 the writing to your system. As with IAnalysisProvider it include 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 though, is register your item serialiser with the platform as follows:

changeGroupService.RegisterDefaultSourceSerilizer(new SharePointVCMigrationItemSerializer());

ProcessChangeGroup

The ProcessChangeGroup method is the most important method of IMigrationProvider as it is called to do the write operation. You are provided a ChangeGroup and the Actions property of that ChangeGroup contains each file/folder/item you need to write/update/delete to your system. The ProcessChangeGroup needs to return a  log of what has happened so that the platform knows all the actions were performed and also so it can correctly tie up item unique ID’s in your system with the other system unique item ID’s. The log is done with a ConversionResult

ConversionResult conversionResult = new ConversionResult(configurationService.MigrationPeer, configurationService.SourceId);

Each action has an Action which tells you what you need to do with the item, be it an update or add or delete etc…

Each action also has an ItemTypeReferenceName which tells you what it is. For WIT this is not too important as you will be dealing with work items, but for VC this very important as it could be a concrete item file or folder or a more theoretical item like a branch or merge instruction.

So you need to loop over all the actions and based on the action + type do the correct thing:

foreach (MigrationAction action in changeGroup.Actions)
{
    if (action.Action == WellKnownChangeActionId.Add || action.Action == WellKnownChangeActionId.Edit)
    {
        if (action.ItemTypeReferenceName == WellKnownContentType.VersionControlledFile.ReferenceName)
        {

Once you have completed your action you need to add the information to the conversion result log. My two adapters do this very differently for no reason other than I wrote the VC adapter much earlier and when I write the WI adapter later I did a more refined generic implementation there. The key part of the adding the information though is below. The most important thing is to provide the ID (the third parameter) to the platform so it knows how to link your item in future which is needed for deletes and updates.

conversionResult.ItemConversionHistory.Add(new ItemConversionHistory(sourceSystemId, string.Empty, newSharePointId.ToString(), string.Empty));

Items and VC

With the VC adapter the way you request the actual file you want is using the Download method on the source item and providing a path.

Power Tip: In my implementation I used the very useful Path.GetTempFileName() from the .NET framework to get a place to put the file. However this causes an empty temp file to be created automatically and the platform doesn’t like that, so I needed to delete the temp file after that, and then call Download.

Power Tip: For folders creation or for deletes of files/folders you can use the Path property of the action to get the folder name.

Items and WIT

WIT is easier when it comes to writing because you do not need to worry about paths and files - you just need to do some XML parsing. All the information about the item will be provided to you in the MigrationActionDescription property of the action and you need to parse that into an item. Since the mapping of field names is handled by the platform this is very simple. In my case the following small method was all I needed to build a list of fields:

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) == false)
        {
            fields.Add(fieldName, fieldValue);
        }
    }

    return fields;
}

Item ID

The platform handles the mapping of item ID’s too, so if you need to know what item needs to be updated or deleted it can be found in the MigrationActionDescription. The following method will work regardless of what your system is:

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;
}