Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System.Net.Http.HttpRequestException: Intermittent Error while Copying Content to a Stream #2608

Closed
nkraman0 opened this issue Aug 5, 2024 · 1 comment
Labels
status:waiting-for-triage An issue that is yet to be reviewed or assigned type:bug A broken experience

Comments

@nkraman0
Copy link

nkraman0 commented Aug 5, 2024

Describe the bug

We are encountering an intermittent issue with the "System.Net.Http.HttpRequestException" while copying content to a stream. The error message is as follows:

System.Net.Http.HttpRequestException: Error while copying content to a stream. —> System.IO.IOException: Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host. —> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host.

Expected behavior

I am encountering an intermittent issue with the "System.Net.Http.HttpRequestException" while copying content to a stream. The below code has been used to upload a file to SharePoint embedded using Graph SDK.

 async public Task WhenValidIDPassed_BulkUploadLargeFileUsingSDK()
 {
     GraphServiceClient graphServiceClient = GraphServiceClientFactory.GetGraphServiceClientAsync();           
     IConfigurationRoot config = ConfigProvider.GetConfigRoot();
     string driveId = config["DriveId"];

     int bulkuploadsize = 0;

     Int32.TryParse(config["BulkUploadSize"], out bulkuploadsize);
     int index = 0;
     string filePathToUpload = config["FilePathToUpload"];
     try
     {
         while (index < bulkuploadsize) // condition
         {
             filePathToUpload = Path.Combine(FileUtils.GetRandomFile());

             using var fileStream = File.OpenRead(filePathToUpload);
             Console.WriteLine($"Upload started for a file {index}  {filePathToUpload}  {DateTime.Now}");

             string newFolderId = Guid.NewGuid().ToString();
             var newDriveItem = new DriveItem()
             {
                 Name = newFolderId,
                 Folder = new Folder(),
                 AdditionalData = new Dictionary<string, object>
         {
             {
                 "@microsoft.graph.conflictBehavior" , "rename"
             },
         }
             };
             var createdDriveItem = await graphServiceClient.Drives[driveId].Items["root"].Children.PostAsync(newDriveItem);
             var folderGraphId = createdDriveItem.Id;

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

             var uploadSession = await graphServiceClient.Drives[driveId]
              .Items[folderGraphId]                 
            .ItemWithPath(filePathToUpload)
            .CreateUploadSession
            .PostAsync(uploadSessionRequestBody);

             int maxSliceSize = 320 * 50 * 1024;
             var fileUploadTask = new LargeFileUploadTask<DriveItem>(
                 uploadSession, fileStream, maxSliceSize, graphServiceClient.RequestAdapter);

             var totalLength = fileStream.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");
             });


             var retries = 0;
             var itemResponse = await UploadFileAsync(fileUploadTask, progress);

             while (retries < 3 && itemResponse == null)
             {
                 var uploadResult = await UploadFileAsync(fileUploadTask, progress, true);
                 retries++;
             }
             Console.WriteLine($"Upload Completed for a file {index} at {DateTime.Now} -  {filePathToUpload} {itemResponse.WebUrl}  ");
             index++;
         }

     }
     catch (ODataError ex)
     {
         Console.WriteLine($"Error uploading: {ex}");

     }
 }

How to reproduce

We are encountering this error intermittently when uploading files larger than 1.5 GB in a loop.

SDK Version

5.34.0

Latest version known to work for scenario above?

No response

Known Workarounds

We are able to upload the same set of files using Graph API. The code snippet has been enclosed below.

 async public Task WhenValidIDPassed_BulkUploadLargeFileUsingAPI2()
 {
     AccessToken tokenCredential = GraphServiceClientFactory.GetGraphServiceTokenAsync();
     IConfigurationRoot config = ConfigProvider.GetConfigRoot();
     var driveId = config["DriveId"];
     var authToken = config["AuthToken"];
     int bulkuploadsize = 0;
     Int32.TryParse(config["BulkUploadSize"], out bulkuploadsize);
     int index = 0;
     string filePathToUpload = config["FilePathToUpload"];
     try
     {
         while (index < bulkuploadsize) // condition
         {
             var filePath = Path.Combine(FileUtils.GetRandomFile());

             var CHUNK_SIZE = 10485760; // 10 MB
             using (var httpClient = new HttpClient())
             {
                 httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenCredential.Token);
                                     var folderName = Guid.NewGuid().ToString();
                 //Create a folder:
                 var createFolderResponse = await CreateFolder(httpClient, driveId, folderName);

                 if (!createFolderResponse.IsSuccessStatusCode)
                 {
                     Console.WriteLine("Failed to create folder.");
                     Console.WriteLine(await createFolderResponse.Content.ReadAsStringAsync());
                     return;
                 }
                   // Create upload session
                 var uploadSessionUri = $"https://graph.microsoft.com/v1.0/drives/{driveId}/items/root:/{folderName}/{Path.GetFileName(filePath)}:/createUploadSession";
                 var uploadSessionResponse = await httpClient.PostAsync(uploadSessionUri, null);
                 uploadSessionResponse.EnsureSuccessStatusCode();

                 var uploadSessionContent = uploadSessionResponse.Content.ReadAsStringAsync().Result;
                 var uploadUrl = JObject.Parse(uploadSessionContent)["uploadUrl"].ToString();
                 Console.WriteLine(uploadUrl);
                 FileInfo fileInfo = new FileInfo(filePath);
                 long size = fileInfo.Length;
                 int chunks = (int)(size / CHUNK_SIZE) + (size % CHUNK_SIZE > 0 ? 1 : 0);

                 using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
                 {
                     int start = 0;

                     for (int chunkNum = 0; chunkNum < chunks; chunkNum++)
                     {
                         byte[] buffer = new byte[CHUNK_SIZE];
                         int bytesRead = await fs.ReadAsync(buffer, 0, CHUNK_SIZE);

                         string uploadRange = $"bytes {start}-{start + bytesRead - 1}/{size}";
                         Console.WriteLine($"chunk: {chunkNum} bytes read: {bytesRead} upload range: {uploadRange}");

                         using (var content = new ByteArrayContent(buffer, 0, bytesRead))
                         {
                             content.Headers.Add("Content-Length", bytesRead.ToString());
                             content.Headers.Add("Content-Range", uploadRange);

                             HttpResponseMessage result = await httpClient.PutAsync(uploadUrl, content);
                             result.EnsureSuccessStatusCode();
                         }

                         start += bytesRead;
                     }

                 }
                
             }
             Console.WriteLine($"Upload Completed for a file {index} at {DateTime.Now} -  {filePathToUpload} {filePath}  ");
             index++;
         }
     }
     catch (Exception ex) { }
 }

Debug output

Click to expand log ```
</details>


### Configuration

_No response_

### Other information

_No response_
@nkraman0 nkraman0 added status:waiting-for-triage An issue that is yet to be reviewed or assigned type:bug A broken experience labels Aug 5, 2024
@andrueastman
Copy link
Member

Thanks for raising this @nkraman0.

If its it's okay, we'll close this this for now to track this via #2609

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status:waiting-for-triage An issue that is yet to be reviewed or assigned type:bug A broken experience
Projects
None yet
Development

No branches or pull requests

2 participants