2

I am trying to upload a file to OneDrive using Graph SDK for .Net Core from worker service. Basically, some files are created at random time and those files needs to be uploaded to specified path on OneDrive from worker service at midnight every day. I have following information stored in appconfig.json file in application:

  • ClientID
  • ClientSecret
  • TenantID

I have checked samples on various sites but could not find how to upload files using above ID and Secret. I believe there must but some kind of authProvider that I could initialize using above ID and Secret.

I also checked miscrosoft's documentation but coudl not find any example on how to upload file using SDK with ID and Secret.

https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/driveitem_put_content?view=odsp-graph-online

Additional Point

  • Upload new file
  • Overwrite if file already exists(hope that graph already supports this)
  • file size is < 4MB
  • path format /folder1/folder2/filename.pdf

Any help would be appreciated.

vishwas-trivedi
  • 516
  • 2
  • 8
  • 26

1 Answers1

1

Remember to assign Application permission (Client credentials flow) to the app registration. See Application permission to Microsoft Graph.

enter image description here

You can use Client credentials provider.

IConfidentialClientApplication confidentialClientApplication = ConfidentialClientApplicationBuilder
    .Create(clientId)
    .WithTenantId(tenantID)
    .WithClientSecret(clientSecret)
    .Build();

ClientCredentialProvider authProvider = new ClientCredentialProvider(confidentialClientApplication);

Upload small file (<4M):

GraphServiceClient graphClient = new GraphServiceClient(authProvider);

using var stream = new System.IO.MemoryStream(Encoding.UTF8.GetBytes("The contents of the file goes here."));

await graphClient.Users[{upn or userID}].Drive.Items["{item-id}"].Content
    .Request()
    .PutAsync<DriveItem>(stream);

If you want to upload large file, see Upload large files with an upload session.

UPDATE:

Use Install-Package Microsoft.Graph.Auth -IncludePrerelease in Tools -> NuGet Package Manager -> Package Manager Console.

It supports both uploading a new file and replacing an existing item.

For how to get the items id, please refer to Get a file or folder.

For example, get the item id of /folder1/folder2 (have a quick test in Microsoft Graph Explorer):

GET https://graph.microsoft.com/v1.0/users/{userID}/drive/root:/folder1:/children

It will list all the children in folder1, including folder2. Then you can find item id of folder2.

UPDATE 2:

Client credentials provider is application identity while all the providers below are user identity.

Since you want to access personal OneDrive (including user identity), you could choose Authorization code provider or Interactive provider.

Authorization code provider: you need to implement interactively sign-in for your web app and use this provider.

Interactive provider: you can easily use this provider to implement interactively sign-in in a console app.

You can have a quick test with the second provider.

Please note that you should add the Delegated (personal Microsoft account) permissions into the app registration. See Delegated permission to Microsoft Graph.

enter image description here

And in this case, you should modify all graphClient.Users[{upn or userID}] to graphClient.Me in your code.

I'm afraid that you have to implement sign-in interactively auth flow to access personal OneDrive.

Allen Wu
  • 15,529
  • 1
  • 9
  • 20
  • Thank you for the answer, Could you please also tell me which nuget packages do I need to use? – vishwas-trivedi Jan 12 '21 at 02:02
  • @JustAProgrammer Install the [Microsoft Graph .NET SDK](https://learn.microsoft.com/en-us/graph/sdks/sdk-installation#install-the-microsoft-graph-net-sdk) – Allen Wu Jan 12 '21 at 02:03
  • Unable to find Microsoft.Graph.Auth NuGet package – vishwas-trivedi Jan 12 '21 at 02:07
  • Microsoft.Graph.Auth is still not production ready, what is the alternative? – vishwas-trivedi Jan 12 '21 at 02:09
  • Also I do not have `item-id`, I just have a path like `/folder1/folder2/file.pdf` – vishwas-trivedi Jan 12 '21 at 02:12
  • @JustAProgrammer See the UPDATE in my answer. – Allen Wu Jan 12 '21 at 02:55
  • Sorry, there seems to be some misunderstanding. I am not sure if `/folder1/folder2` exists. If it does not exists then I would like to create it. – vishwas-trivedi Jan 12 '21 at 03:20
  • @JustAProgrammer See https://learn.microsoft.com/en-us/graph/api/driveitem-post-children?view=graph-rest-1.0&tabs=csharp. – Allen Wu Jan 12 '21 at 03:50
  • I tried to create a file in root directory using `graphClient.Me.Drive.Root.Content.Request().PutAsync(stream);` but I am getting `Tenant does not have a SPO license` error. I already have office 365 subscription and also registered my app in azure portal but it does not work. – vishwas-trivedi Jan 12 '21 at 06:14
  • @JustAProgrammer Did you assign a SPO license (shrepoint online license) to your account? See this answer. https://stackoverflow.com/questions/59159530/tenant-does-not-have-a-spo-license-when-using-microsoft-graph-api-with-applicati?answertab=votes#tab-top – Allen Wu Jan 12 '21 at 06:21
  • Sorry but why do I need SPO license? Does this mean I have to get business license? I have personal subscription od O365 – vishwas-trivedi Jan 12 '21 at 06:38
  • @JustAProgrammer Because you are trying to upload file to your OneDrive for business. So what you want to do is uploading file to your personal OneDrive? – Allen Wu Jan 12 '21 at 06:57
  • @JustAProgrammer Have added an **UPDATE 2** in the answer. – Allen Wu Jan 12 '21 at 07:24
  • Will this work though? because I am trying to access from worker service? If I user delegate then I have to show authentication dialog to user, isn't it? – vishwas-trivedi Jan 12 '21 at 07:34
  • @JustAProgrammer If you use Username/password provider, you don't need to sign in interactively. See the sample I provided in the end. But with this method, you have to hardcode the username and password in your code. And can only upload the file to this user's OneDrive. – Allen Wu Jan 12 '21 at 07:35
  • Thanks, I checked your answer but why can't I use tenant ID and secret in persoanl account? – vishwas-trivedi Jan 12 '21 at 07:59
  • @JustAProgrammer In fact you can. Whether do use client secret depends on the type of the Azure AD app. If your app is a public client, then the client_secret cannot be included. If the app is a confidential client, then it must be included. The official sample uses public client app, so the client secret is not used here, but tenant id is used. – Allen Wu Jan 12 '21 at 08:47
  • Okay, understood your point but then why am I getting `Tenant does not have a SPO license` when I am trying to access personal drive. – vishwas-trivedi Jan 12 '21 at 09:00
  • @JustAProgrammer Oh sorry, I made a mistake. For personal OneDrive, ROPC flow is not supported. You have to implement sign-in interactively to access personal OneDrive. See a discussion in this answer: https://stackoverflow.com/questions/65327473/microsoft-graph-api-unkownerror?answertab=votes#tab-top – Allen Wu Jan 12 '21 at 09:04
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/227180/discussion-between-allen-wu-and-justaprogrammer). – Allen Wu Jan 12 '21 at 09:04
  • Okay, understood. So I can not use ID and secret for personal account. So I will have to go with business account of OneDrive. I'll try the above code with business account and accept the answer if this works. Thanks! – vishwas-trivedi Jan 12 '21 at 09:13
  • @JustAProgrammer For business account (O365 work account), you can follow the steps of "Client credentials provider", which uses Application permission. See the beginning of my answer. Good luck! – Allen Wu Jan 12 '21 at 09:19
  • @JustAProgrammer Any updates on this issue? – Allen Wu Jan 20 '21 at 06:26
  • How to do that with Graph .NET SDK v5.0, something has been changed, the old way of doing, graphClient.Me.Drive.Root.ItemWithPath(name).Content.PutAsync, is not working. Any idea how? – Snekithan Jun 01 '23 at 21:18