Search code examples
c#microsoft-graph-apiattachmentlarge-files

Access token empty error when uploading large files to a ToDoTask using Graph Api


I am trying to attach large files to a ToDoTask using the Graph Api using the example in the docs for attaching large files for ToDoTask and the recommend class LargeFileUploadTask for uploading large files.

I have done this sucessfully before with attaching large files to emails and sending so i used that as base for the following method.

public async Task CreateTaskBigAttachments( string idList, string title, List<string> categories,
    BodyType contentType, string content, Importance importance, bool isRemindOn, DateTime? dueTime, cAttachment[] attachments = null)
{
    try
    {
        var _newTask = new TodoTask
        {
            Title = title,
            Categories = categories,
            Body = new ItemBody()
            {
                ContentType = contentType,
                Content = content,

            },
            IsReminderOn = isRemindOn,
            Importance = importance
        };
        if (dueTime.HasValue)
        {
            var _timeZone = TimeZoneInfo.Local;
            _newTask.DueDateTime = DateTimeTimeZone.FromDateTime(dueTime.Value, _timeZone.StandardName);
        }
        var _task = await _graphServiceClient.Me.Todo.Lists[idList].Tasks.Request().AddAsync(_newTask);
        //Add attachments
        if (attachments != null)
        {
            if (attachments.Length > 0)
            {
                foreach (var _attachment in attachments)
                {
                    var _attachmentContentSize = _attachment.ContentBytes.Length;
                    var _attachmentInfo = new AttachmentInfo
                    {
                        AttachmentType = AttachmentType.File,
                        Name = _attachment.FileName,
                        Size = _attachmentContentSize,
                        ContentType = _attachment.ContentType
                    };
                    var _uploadSession = await _graphServiceClient.Me
                        .Todo.Lists[idList].Tasks[_task.Id]
                        .Attachments.CreateUploadSession(_attachmentInfo).Request().PostAsync();
                    using (var _stream = new MemoryStream(_attachment.ContentBytes))
                    {
                        _stream.Position = 0;
                        LargeFileUploadTask<TaskFileAttachment> _largeFileUploadTask = new LargeFileUploadTask<TaskFileAttachment>(_uploadSession, _stream, MaxChunkSize);
                        try
                        {
                            await _largeFileUploadTask.UploadAsync();
                        }
                        catch (ServiceException errorGraph)
                        {
                            if (errorGraph.StatusCode == HttpStatusCode.InternalServerError || errorGraph.StatusCode == HttpStatusCode.BadGateway
                                || errorGraph.StatusCode == HttpStatusCode.ServiceUnavailable || errorGraph.StatusCode == HttpStatusCode.GatewayTimeout)
                            {
                                Thread.Sleep(1000); //Wait time until next attempt
                                //Try again
                                await _largeFileUploadTask.ResumeAsync();
                            }
                            else
                                throw errorGraph;
                        }
                    }
                }

            }

        }
    }
    catch (ServiceException errorGraph)
    {
        throw errorGraph;
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

Up to the point of creating the task everything goes well, it does create the task for the user and its properly shown in the user tasks list. Also, it does create an upload session properly.

The problem comes when i am trying to upload the large file in the UploadAsync instruction.

The following error happens.

Code: InvalidAuthenticationToken Message: Access token is empty.

But according to the LargeFileUploadTask doc , the client does not need to set Auth Headers.

param name="baseClient" To use for making upload requests. The client should not set Auth headers as upload urls do not need them.

Is not LargeFileUploadTask allowed to be used to upload large files to a ToDoTask? If not then what is the proper way to upload large files to a ToDoTask using the Graph Api, can someone provide an example?


Solution

  • It seems like its a bug and they are working on it.

    Temporarily I did this code to deal with the issue of the large files.

    var _task = await _graphServiceClient.Me.Todo.Lists[idList].Tasks.Request().AddAsync(_newTask);
    //Add attachments
    if (attachments != null)
    {
    if (attachments.Length > 0)
    {
    foreach (var _attachment in attachments)
    {
    var _attachmentContentSize = _attachment.ContentBytes.Length;
    var _attachmentInfo = new AttachmentInfo
    {
    AttachmentType = AttachmentType.File,
    Name = _attachment.FileName,
    Size = _attachmentContentSize,
    ContentType = _attachment.ContentType
    };
    var _uploadSession = await _graphServiceClient.Me
    .Todo.Lists[idList].Tasks[_task.Id]
    .Attachments.CreateUploadSession(_attachmentInfo).Request().PostAsync();
    // Get the upload URL and the next expected range from the response
    string _uploadUrl = _uploadSession.UploadUrl;
    using (var _stream = new MemoryStream(_attachment.ContentBytes))
    {
    _stream.Position = 0;
    
    // Create a byte array to hold the contents of each chunk
    byte[] _chunk = new byte[MaxChunkSize];
    //Bytes to read
    int _bytesRead = 0;
    //Times the stream has been read
    var _ind = 0;
    while ((_bytesRead = _stream.Read(_chunk, 0, _chunk.Length)) > 0)
    {
    
    // Calculate the range of the current chunk
    string _currentChunkRange = $"bytes {_ind * MaxChunkSize}-{_ind * MaxChunkSize + _bytesRead - 1}/{_stream.Length}";
    //Despues deberiamos calcular el next expected range en caso de ocuparlo
    
    
    // Create a ByteArrayContent object from the chunk
    ByteArrayContent _byteArrayContent = new ByteArrayContent(_chunk, 0, _bytesRead);
    
    // Set the header for the current chunk
    _byteArrayContent.Headers.Add("Content-Range", _currentChunkRange);
    _byteArrayContent.Headers.Add("Content-Type", _attachment.ContentType);
    _byteArrayContent.Headers.Add("Content-Length", _bytesRead.ToString());
    // Upload the chunk using the httpClient Request
    var _client = new HttpClient();
    var _requestMessage = new HttpRequestMessage()
    {
    RequestUri = new Uri(_uploadUrl + "/content"),
    Method = HttpMethod.Put,
    Headers =
    {
    { "Authorization", bearerToken },
    }
    };
    _requestMessage.Content = _byteArrayContent;
    var _response = await _client.SendAsync(_requestMessage);
    if (!_response.IsSuccessStatusCode)
    throw new Exception("File attachment failed");
    _ind++;
    }
    }
    }
    
    }
    
    }