7

Trying to upload a file to onedrive that does not already exist. I have managed to get it to update an existing file. But can't seem to figure out how to create a brand new file. I have done this useing the Microsoft.Graph library.

Here is the code that works to update an existing file:

public async Task<ActionResult> OneDriveUpload()
    {
        string token = await GetAccessToken();
        if (string.IsNullOrEmpty(token))
        {
            // If there's no token in the session, redirect to Home
            return Redirect("/");
        }

        GraphServiceClient client = new GraphServiceClient(
            new DelegateAuthenticationProvider(
                (requestMessage) =>
                {
                    requestMessage.Headers.Authorization =
                        new AuthenticationHeaderValue("Bearer", token);

                    return Task.FromResult(0);
                }));


        try
        {
            string path = @"C:/Users/user/Desktop/testUpload.xlsx";
            byte[] data = System.IO.File.ReadAllBytes(path);
            Stream stream = new MemoryStream(data);
            // Line that updates the existing file             
            await client.Me.Drive.Items["55BBAC51A4E4017D!104"].Content.Request().PutAsync<DriveItem>(stream);

            return View("Index");
        }
        catch (ServiceException ex)
        {
            return RedirectToAction("Error", "Home", new { message = "ERROR retrieving messages", debug = ex.Message });
        }
    }
Azuraith
  • 1,030
  • 14
  • 28
  • Can you provide error information from Fiddler? One thing I do see is that you should dispose of the stream. Use `using (Stream stream = new MemoryStream(data)) { //put your call here }` – Michael Mainer Apr 16 '18 at 19:57

2 Answers2

12

I'd suggest using the ChunkedUploadProvider utility that is included in the SDK. Aside from being a little easier to work with, it will allow you to upload files of any side rather than being limited to files under 4MB.

You can find a sample of how to use ChunkedUploadProvider in the OneDriveUploadLargeFile unit test.

To answer your direct question, uploading works the same for both replacing and creating files. You do however need to specify the file name rather than just an existing Item number:

await graphClient.Me
    .Drive
    .Root
    .ItemWithPath("fileName")
    .Content
    .Request()
    .PutAsync<DriveItem>(stream);
Marc LaFleur
  • 31,987
  • 4
  • 37
  • 63
  • 1
    Thanks! I will look into ChunkedUploadProvider. However, i doubt i will need it as all files being uploaded are very small. Thnaks for helping me up. This was crucial. – Azuraith Apr 13 '18 at 19:02
  • 2
    For the general case: await GraphClient .Me .Drive .Items["folderID"] .ItemWithPath("fileName") .Content .Request() .PutAsync(stream); – Trevy Burgess Jan 22 '20 at 21:39
  • @MarcLaFleur I was wondering if you would have time to suggest/comment on my similar post [here](https://stackoverflow.com/q/62725442/1232087). I'm following your suggested code above, but getting an error. Maybe, I'm missing something in my code. – nam Jul 04 '20 at 17:31
0

This code will help you all to upload small and large files using Microsoft graph Api Sdk in ASP .NEt Core

Upload or replace the contents of a DriveItem

*Controller code : -*      
  [BindProperty]
        public IFormFile UploadedFile { get; set; }
        public IDriveItemChildrenCollectionPage Files { get; private set; }

        public FilesController(ILogger<FilesModel> logger, GraphFilesClient graphFilesClient, GraphServiceClient graphServiceClient, ITokenAcquisition tokenAcquisition)
        {
            _graphFilesClient = graphFilesClient;
            _logger = logger;
            _graphServiceClient = graphServiceClient;
            _tokenAcquisition = tokenAcquisition;
        }


[EnableCors]
        [HttpPost]
        [Route("upload-file")]
        [RequestFormLimits(MultipartBodyLengthLimit = 100000000)]
        [RequestSizeLimit(100000000)]
        public async Task<IActionResult> uploadFiles(string itemId, string folderName, [FromHeader] string accessToken)
        {

            _logger.LogInformation("into controller");
            if (UploadedFile == null || UploadedFile.Length == 0)
            {
                return BadRequest();
            }

            _logger.LogInformation($"Uploading {UploadedFile.FileName}.");

            var filePath = Path.Combine(System.IO.Directory.GetCurrentDirectory(), UploadedFile.FileName);
            _logger.LogInformation($"Uploaded file {filePath}");


            using (var stream = new MemoryStream())
            {

                UploadedFile.CopyTo(stream);
                var  bytes = stream.ToArray();
                _logger.LogInformation($"Stream {stream}.");
                stream.Flush();
                await _graphFilesClient.UploadFile(
                UploadedFile.FileName, new MemoryStream(bytes), itemId, folderName, accessToken);
            }

            return Ok("Upload Successful!");
        }

*Service code :-* 

 [EnableCors]
        public async Task UploadFile(string fileName, Stream stream,string itemId,string folderName,string accessToken)
        {

            GraphClients graphClients = new GraphClients(accessToken);
            GraphServiceClient _graphServiceClient = graphClients.getGraphClient();
            _logger.LogInformation("Into Service");

            var filePath = Path.Combine(System.IO.Directory.GetCurrentDirectory(),fileName);

            _logger.LogInformation($"filepath : {filePath}");

            Console.WriteLine("Uploading file: " + fileName);

            var size = stream.Length / 1000;
            _logger.LogInformation($"Stream size: {size} KB");
            if (size/1000 > 4)
            {
                // Allows slices of a large file to be uploaded 
                // Optional but supports progress and resume capabilities if needed
                await UploadLargeFile(filePath, stream,accessToken);
            }
            else
            {
                try
                {
                    _logger.LogInformation("Try block");

                    String test = folderName + "/" + fileName;
                    // Uploads entire file all at once. No support for reporting progress.
// for getting your sharepoint site open graph explorer > sharepoint sites > get my organization's default sharepoint site.


                    var driveItem = await _graphServiceClient
                        .Sites["Your share point site"]
                        .Drive
                        .Root.ItemWithPath(test)
                        .Content
                        .Request()
                        .PutAsync<DriveItem>(stream);
                    _logger.LogInformation($"Upload complete: {driveItem.Name}");
                }
                catch (ServiceException ex)
                {
                    _logger.LogError($"Error uploading: {ex.ToString()}");
                    throw;
                }
            }
        }


        private async Task UploadLargeFile(string itemPath, Stream stream,string accessToken)
        {
            GraphClients graphClients = new GraphClients(accessToken);
            GraphServiceClient _graphServiceClient = graphClients.getGraphClient();
            // Allows "slices" of a file to be uploaded.
            // This technique provides a way to capture the progress of the upload
            // and makes it possible to resume an upload using fileUploadTask.ResumeAsync(progress);
            // Based on https://docs.microsoft.com/en-us/graph/sdks/large-file-upload

            // Use uploadable properties to specify the conflict behavior (replace in this case).
            var uploadProps = new DriveItemUploadableProperties
            {
                ODataType = null,
                AdditionalData = new Dictionary<string, object>
                {
                    { "@microsoft.graph.conflictBehavior", "replace" }
                }
            };

            // Create the upload session
            var uploadSession = await _graphServiceClient.Me.Drive.Root
                                    .ItemWithPath(itemPath)
                                    .CreateUploadSession(uploadProps)
                                    .Request()
                                    .PostAsync();

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

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

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

                if (uploadResult.UploadSucceeded)
                {
                    _logger.LogInformation($"Upload complete, item ID: {uploadResult.ItemResponse.Id}");
                }
                else
                {
                    _logger.LogInformation("Upload failed");
                }

            }
            catch (ServiceException ex)
            {
                _logger.LogError($"Error uploading: {ex.ToString()}");
                throw;
            }
        }