如何同时将单个 IFormFile 复制到多个内存流

问题描述 投票:0回答:1

我有一个 IFormFile,我将其作为参数传递给两个单独的异步函数,这两个函数将 IFormFile 转换为内存流,其中一个通过 ms graph 上传到 OneDrive,另一个通过 Box SDK 上传到 Box。但是,在 OneDrive 中的 copyToAsync() 行,有时它可以工作,有时会失败。看来您一次只能复制一个?由于加载到这些云服务的速度较慢,我真的想使用异步来使事情变得更快一些。我的代码错误如下:

The inner stream position has changed unexpectedly.
       at Microsoft.AspNetCore.Http.ReferenceReadStream.VerifyPosition()
   at Microsoft.AspNetCore.Http.ReferenceReadStream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken)
   at System.IO.Stream.<CopyToAsync>g__Core|27_0(Stream source, Stream destination, Int32 bufferSize, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Http.FormFile.CopyToAsync(Stream target, CancellationToken cancellationToken)
   at ARMS_API.Repositories.OneDriveRepository.UploadFileByPathAsync(IFormFile file, String DestinationPath, String RootFolderId) in /Users/baun/Documents/ARMS-API/ARMS-API/Repositories/OneDriveCloudStorage.cs:line 45
   at ARMS_API.Services.CertificationReviewService`1.AddCertificationAsync(IFormFile file, AddDocumentPOCO addDocumentPOCO) in /Users/baun/Documents/ARMS-API/ARMS-API/Features/CertificationReview/CertificationReviewService.cs:line 89
   at ARMS_API.Services.CertificationReviewService`1.AddCertificationReviewAsync(AddCertificationReviewDTO addCertificationReviewDTO) in /Users/baun/Documents/ARMS-API/ARMS-API/Features/CertificationReview/CertificationReviewService.cs:line 74
   at ARMS_API.Controllers.CertificationReviewController.AddCertificationReview(AddCertificationReviewDTO addCertificationReviewDTO) in /Users/baun/Documents/ARMS-API/ARMS-API/Features/CertificationReview/CertificationReviewController.cs:line 46

实现(我使用了一些相同的功能,但略有不同):

        public async Task<List<DocumentDTO>> AddSupportingDocumentsAsync(AddDocumentsDTO addDocumentsDTO)
    {
        if(addDocumentsDTO.Files.Count > 0)
        {
            var currentUser = await _userService.GetByAccessTokenAsync();
            var addDocumentsPOCO = await _documentsRepository.AddSupportingDocumentsAsync(addDocumentsDTO, currentUser);

            var documentsDTO = new List<DocumentDTO>();
            var tasks = addDocumentsPOCO.Select( async file => {
                var document = addDocumentsDTO.Files.Where(item => item.FileName.Equals(file.FILENAME_AT_UPLOAD, StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
                
                var oneDriveDocumentTask =  _oneDriveRepository.UploadFileByPathAsync(document!,Path.Combine(_armsBaseFolderPath, file.DOCUMENT_PATH!, file.DOCUMENT_FILENAME!),_rootOneDriveFolderId);
                var boxDocumentTask =  _boxRepository.UploadFileByPathAsync(document!,Path.Combine(file.DMCP_DOCUMENT_PATH!, file.DOCUMENT_FILENAME!),_rootBoxFolderId);
                List<Task> cloudStorageTasks = new List<Task>(){oneDriveDocumentTask,boxDocumentTask};

                await Task.WhenAll(cloudStorageTasks);

                documentsDTO.Add(new DocumentDTO{
                    MmcidForDisplay = file.MMCIDForDisplay,
                    Mmcid = file.MMCID,
                    FilenameAtUpload = file.FILENAME_AT_UPLOAD,
                    DocGroupTypeDd = file.DOC_GROUP_TYPE_DD,
                    DocIterationCount = file.DOC_ITERATION_COUNT,
                    DocTypeDd = file.DOC_TYPE_DD,
                    WhoUploaded = file.WHO_UPLOADED,
                    DmcpBoxId = file.DMCP_BOX_ID,
                    DmcpDocumentPath = file.DMCP_DOCUMENT_PATH,
                    OactDocumentPath = file.DOCUMENT_PATH,
                    DocumentFilename = file.DOCUMENT_FILENAME
                });
            });

            await Task.WhenAll(tasks);

            return documentsDTO;
        }

        return null;
    }

OneDrive:

public async Task<Models.CloudStorage?> UploadFileByPathAsync(IFormFile file, string DestinationPath, string RootFolderId)
{
    using(var memoryStream = new MemoryStream())
    {
        // Use properties to specify the conflict behavior
        // in this case, replace
        await file.CopyToAsync(memoryStream);
        memoryStream.Position = 0;

        var oneDriveUpload = await UploadOneDrive(memoryStream, DestinationPath, RootFolderId);
        return oneDriveUpload;
    }
}

private async Task<Models.CloudStorage?> UploadOneDrive(MemoryStream SourceFile, string DestinationPath, string RootFolderId)
{
    using var memoryStream = SourceFile;

    // Use properties to specify the conflict behavior
    // in this case, replace

    var uploadSessionRequestBody = new CreateUploadSessionPostRequestBody
    {
        Item = new DriveItemUploadableProperties
        {
            AdditionalData = new Dictionary<string, object>
            {
                { "@microsoft.graph.conflictBehavior", "replace" },
            },
        },
    };

    // Create the upload session
    // itemPath does not need to be a path to an existing item
    var uploadSession = await _graphServiceClient!.Drives[RootFolderId].Root
        .ItemWithPath(DestinationPath)
        .CreateUploadSession
        .PostAsync(uploadSessionRequestBody);


    // Max slice size must be a multiple of 320 KiB
    int maxSliceSize = 320 * 1024;
    var fileUploadTask =
        new LargeFileUploadTask<DriveItem>(uploadSession, memoryStream, maxSliceSize);

    var totalLength = memoryStream.Length;
    // Create a callback that is invoked after each slice is uploaded
    IProgress<long> progress = new Progress<long>(prog => {
        Console.WriteLine($"Uploaded {prog} bytes of {totalLength} bytes");
    });

    // Upload the file
    var uploadResult = await fileUploadTask.UploadAsync(progress);

    if (uploadResult.UploadSucceeded)
    {
        var response = uploadResult.ItemResponse;

        var cloudStorage = new Models.CloudStorage () {
            CloudStorageProvider = "OneDrive",
            Id = response.Id!,
            FileName = response.Name!,
            WebURL = response.WebUrl!,
            DownloadLink = null
        };

        return cloudStorage;
    }
    else
    {
        return null;
    }


}

盒子:

public async Task<Models.CloudStorage?> UploadFileByPathAsync(IFormFile file, string DestinationPath, string RootFolderId)
    {
        using(var memoryStream = new MemoryStream())
        {
            await file.CopyToAsync(memoryStream);
            memoryStream.Position = 0;

            var boxUpload = await BoxUpload(memoryStream, DestinationPath, RootFolderId);
            return boxUpload;
        }
    }
    
    private async Task<Models.CloudStorage?> BoxUpload(MemoryStream SourceFile, string DestinationPath, string RootFolderId)
    {
        BoxClient adminClient = _session.AdminClient(await token.FetchTokenAsync());

        string[] directories = Path.GetDirectoryName(DestinationPath)!.Split(Path.DirectorySeparatorChar);
        string PrevParentFolderID = RootFolderId;
        
        //finding the folder
        try
        {
            foreach (var folderItem in directories)
            {
                var limit = 1000;
                var currentFolder = await adminClient.FoldersManager.GetFolderItemsAsync(id: PrevParentFolderID,1);
                var totalItems = currentFolder.TotalCount;

                for (int offset = 0; offset < totalItems; offset+=limit)
                {
                    var folderItems = await adminClient.FoldersManager.GetFolderItemsAsync(id: PrevParentFolderID, limit, offset);
                    if(folderItems.Entries.Any(x => x.Name.Equals(folderItem, StringComparison.OrdinalIgnoreCase)))
                    {
                        PrevParentFolderID = folderItems.Entries.Find(x => x.Name.Equals(folderItem, StringComparison.OrdinalIgnoreCase))!.Id;
                        break;
                    }
                    else
                    {
                        if(offset+limit>=totalItems)
                        {
                            try
                            {
                                // Create a new folder in the user's root folder
                                var folderParams = new BoxFolderRequest()
                                {
                                    Name = folderItem.ToString(),
                                    Parent = new BoxRequestEntity() { Id = PrevParentFolderID }
                                };
                                BoxFolder folder = await adminClient.FoldersManager.CreateAsync(folderParams);
                                PrevParentFolderID = folder.Id;
                                break;
                            }
                            catch(BoxException ex)
                            {
                                var ExJson = JsonSerializer.Deserialize<dynamic>(ex.Message)!;
                                PrevParentFolderID = ExJson["context_info"]["conflicts"][0]["id"];
                                break;
                            }
                        }
                    }
                }
            }
        }
        catch (BoxException ex)
        {
            dynamic ExJson = JsonSerializer.Deserialize<dynamic>(ex.Message)!;
            return null;
        }
        //file upload once folder id is found
        try
        {
            BoxFile file;

            using (var fileStream = SourceFile)
            {
                var fileSizeInMB = fileStream.Length / (1024 * 1024);
                if (fileSizeInMB <= 50 )
                {
                    BoxFileRequest requestParams = new BoxFileRequest()
                    {
                        Name = Path.GetFileName(DestinationPath),
                        Parent = new BoxRequestEntity() { Id = PrevParentFolderID }
                    };

                    file = await adminClient.FilesManager.UploadAsync(requestParams, fileStream);

                }
                else
                {
                    var progress = new Progress<BoxProgress>(val => {
                        Console.WriteLine("Uploaded {0}%", val.progress);
                    });

                    file = await adminClient.FilesManager.UploadUsingSessionAsync(fileStream, Path.GetFileName(DestinationPath), PrevParentFolderID, null, progress);
                    
                }
            }

            var cloudStorage = new Models.CloudStorage () {
                CloudStorageProvider = "Box",
                Id = file.Id,
                FileName = file.Name,
                WebURL = _productionDomain + "/file/" + file.Id,
                DownloadLink = null
            };

            return cloudStorage;
        }
        catch (BoxException ex)
        {
            dynamic ExJson = JsonSerializer.Deserialize<dynamic>(ex.Message)!;
            return null;
        }
    }
asp.net-core microsoft-graph-api memorystream boxsdk
1个回答
0
投票

当您使用流时,有时光标(又名位置)会移动到流的末尾,您必须将位置移回 0,您尝试过吗?

© www.soinside.com 2019 - 2024. All rights reserved.