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

"Must provide stream that can read and seek" Large File attachment. #2249

Closed
Ofer-Gal opened this issue Dec 12, 2023 · 3 comments
Closed

"Must provide stream that can read and seek" Large File attachment. #2249

Ofer-Gal opened this issue Dec 12, 2023 · 3 comments

Comments

@Ofer-Gal
Copy link

Ofer-Gal commented Dec 12, 2023

To Reproduce In an Azure Function
Steps to reproduce the behavior:

  1. Download The file Stream memStream = await _graphClient.Drives[drive.Id].Items[driveItem.Id].Content.GetAsync();
  2. Create session : var uploadSession = await _graphClient.Users[sender].Messages[draft.Id].Attachments.CreateUploadSession.PostAsync(requestBody);
  3. Create the task: var fileUploadTask = new LargeFileUploadTask<DriveItem>(uploadSession, fileStream, maxSliceSize);
  4. Get Error :'Must provide stream that can read and seek'

Expected behavior
Create the task and continue upload like this code has done in the last year

Desktop (please complete the following information):

  • OS: [Azure]

Additional context
Seems the upload expects a FileStream but the "Download" returns a Memory Stream (Which was OK until few days ago)
I did not find a way to create a FileStream without saving to disk. I have no disk in an Azure Function.

Thanks.

@andrueastman
Copy link
Member

Thanks for raising this @Ofer-Gal

For performance reasons, the stream returned by the await _graphClient.Drives[drive.Id].Items[driveItem.Id].Content.GetAsync(); is not buffered by default.

As in this scenario, you need a buffered stream, any chance the suggestion below works for you?

            Stream memStream = await _graphClient.Drives["drive-id"].Items["drive-item-id"].Content.GetAsync();
            using var bufferedStream = new MemoryStream();
            await memStream.CopyToAsync(bufferedStream);//buffer the stream so that its seekable.
            var fileUploadTask =  new LargeFileUploadTask<DriveItem>(uploadSession, bufferedStream, maxSliceSize);

@Ofer-Gal
Copy link
Author

This works fine thank you.
Maybe such "Issue" should be mentioned in the documentation?

@Nijasbijilyrawther
Copy link

@andrueastman
Its not possible for us to load the entire stream into memory because of the sheer size of the file and will need to work with a HttpResponseStream fetched via HttpClient.

How can we use such a stream on this endpoint to upload a large file ?

`using (var httpResponse = await httpClientStorageService.GetAsync(downloadStorageServiceURLPath, HttpCompletionOption.ResponseHeadersRead))
{
using (var httpResponseStream = await httpResponse.Content.ReadAsStreamAsync())
{
if (httpResponse.Content.Headers.ContentLength != null)
{
long contentLength = (long)httpResponse.Content.Headers.ContentLength;
_logger.LogInformation("Content Length " + contentLength);

        var clientSecretCredential = new ClientSecretCredential(
            tenantId: "*******",
            clientId: "********",
            clientSecret: "******"
        );
        var graphClient = new GraphServiceClient(clientSecretCredential, new[] { "https://graph.microsoft.com/.default" });
        var requestBody = new Microsoft.Graph.Drives.Item.Items.Item.CreateUploadSession.CreateUploadSessionPostRequestBody
        {
        };
        var uploadSessionss = await graphClient
        .Drives[libraryId]
        .Items["root"]
        .ItemWithPath(documentName)
        .CreateUploadSession
        .PostAsync(requestBody);
    
    
        int maxChunkSize = 320 * 1024;  // Max slice size must be a multiple of 320 KiB
        var uploadTask = new LargeFileUploadTask<DriveItem>(uploadSessionss, new CustomLengthStream(httpResponseStream, contentLength), maxChunkSize, graphClient.RequestAdapter);
    
        IProgress<long> progress = new Progress<long>(prog =>
        {
            Console.WriteLine($"Uploaded {prog} bytes.");
        });
    
        try
        {
            var uploadResult = await uploadTask.UploadAsync(progress);
            ........
    `

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants