private async Task UploadAttachmentFromSourceRelation()

in Common/Migration/Phase2/Processors/AttachmentsProcessor.cs [118:206]


        private async Task<AttachmentLink> UploadAttachmentFromSourceRelation(IMigrationContext migrationContext, IBatchMigrationContext batchContext, WorkItem sourceWorkItem, WorkItemRelation sourceRelation, int maxAttachmentSize)
        {
            //Attachments are of type Rel = "AttachedFile"
            if (sourceRelation.Rel == Constants.AttachedFile)
            {
                string filename = null;
                string comment = null;
                long resourceSize = 0;
                //get the file name and comment  
                if (sourceRelation.Attributes.ContainsKey(Constants.RelationAttributeName))
                {
                    filename = sourceRelation.Attributes[Constants.RelationAttributeName].ToString();
                }
                if (sourceRelation.Attributes.ContainsKey(Constants.RelationAttributeComment))
                {
                    comment = sourceRelation.Attributes[Constants.RelationAttributeComment].ToString();
                }
                //get the guid from the url
                Guid attachmentId;
                if (Guid.TryParse(sourceRelation.Url.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries).Last(), out attachmentId))
                {
                    Stream stream = null;
                    try
                    {
                        Logger.LogTrace(LogDestination.File, $"Reading attachment {filename} for source work item {sourceWorkItem.Id} from the source account");
                        stream = await WorkItemTrackingHelpers.GetAttachmentAsync(migrationContext.SourceClient.WorkItemTrackingHttpClient, attachmentId);
                        Logger.LogTrace(LogDestination.File, $"Completed reading attachment {filename} for source work item {sourceWorkItem.Id} from the source account");
                    }
                    catch (Exception e)
                    {
                        Logger.LogError(LogDestination.File, e, $"Unable to download attachment {filename} for source work item {sourceWorkItem.Id} from the source account");
                        ClientHelpers.AddFailureReasonToWorkItemMigrationState(sourceWorkItem.Id.Value, FailureReason.AttachmentDownloadError, batchContext.WorkItemMigrationState);
                        return null;
                    }

                    AttachmentReference aRef = null;
                    using (MemoryStream memstream = new MemoryStream())
                    {
                        using (stream)
                        {
                            try
                            {
                                Logger.LogTrace(LogDestination.File, $"Downloading attachment {filename} for source work item {sourceWorkItem.Id} from the source account");
                                await ClientHelpers.CopyStreamAsync(stream, memstream);
                                Logger.LogTrace(LogDestination.File, $"Completed downloading attachment {filename} for source work item {sourceWorkItem.Id} from the source account");
                            }
                            catch (Exception e)
                            {
                                Logger.LogError(LogDestination.File, e, $"Unable to read downloaded attachment {filename} for source work item {sourceWorkItem.Id} from the source account");
                                ClientHelpers.AddFailureReasonToWorkItemMigrationState(sourceWorkItem.Id.Value, FailureReason.AttachmentDownloadError, batchContext.WorkItemMigrationState);
                                return null;
                            }
                        }

                        resourceSize = memstream.Length;
                        if (resourceSize > maxAttachmentSize)
                        {
                            Logger.LogWarning(LogDestination.File, $"Attachment of source work item with id {sourceWorkItem.Id} and url {sourceRelation.Url} exceeded the maximum attachment size of {maxAttachmentSize} bytes." +
                                $" Skipping creating the attachment in target account.");
                            return null;
                        }
                        memstream.Position = 0;
                        //upload the attachment to the target
                        try
                        {
                            Logger.LogTrace(LogDestination.File, $"Uploading attachment {filename} of {resourceSize} bytes for source work item {sourceWorkItem.Id} from the source account");
                            aRef = await WorkItemTrackingHelpers.CreateAttachmentChunkedAsync(migrationContext.TargetClient.WorkItemTrackingHttpClient, migrationContext.TargetClient.Connection, memstream, migrationContext.Config.AttachmentUploadChunkSize);
                            Logger.LogTrace(LogDestination.File, $"Completed uploading attachment {filename} for source work item {sourceWorkItem.Id} from the source account");
                        }
                        catch (Exception e)
                        {
                            Logger.LogError(LogDestination.File, e, $"Unable to upload attachment {filename} for source work item {sourceWorkItem.Id} to the target account");
                            ClientHelpers.AddFailureReasonToWorkItemMigrationState(sourceWorkItem.Id.Value, FailureReason.AttachmentUploadError, batchContext.WorkItemMigrationState);
                        }
                    }
                    if (aRef != null)
                    {
                         return new AttachmentLink(filename, aRef, resourceSize, comment);
                    }
                }
                else
                {
                    Logger.LogError(LogDestination.File, $"Attachment link is incorrect for {sourceWorkItem.Id} {sourceRelation.Url}. Skipping creating the attachment in target account.");
                    ClientHelpers.AddFailureReasonToWorkItemMigrationState(sourceWorkItem.Id.Value, FailureReason.AttachmentUploadError, batchContext.WorkItemMigrationState);
                }
            }

            return null;
        }