Are you working on an application that needs download files from a users Google Drive account. I am going to show you how to do that using C# and the Google .Net Client library.
Prerequisite
The first thing we will need to do is import the Google Drive API v3 NuGet package
Install-Package Google.Apis.Drive.v3
Authenticate
File list is private data which means it is owned by a user. In order to access it you must be authenticated to that user. We also need a users permission to download the file once we have listed it.
/// <summary>
/// This method requests Authentcation from a user using Oauth2.
/// Credentials are stored in System.Environment.SpecialFolder.Personal
/// Documentation https://developers.google.com/accounts/docs/OAuth2
/// </summary>
/// <param name="clientSecretJson">Path to the client secret json file from Google Developers console.</param>
/// <param name="userName">Identifying string for the user who is being authentcated.</param>
/// <returns>DriveService used to make requests against the Drive API</returns>
public static DriveService AuthenticateOauth(string clientSecretJson, string userName)
{
try
{
if (string.IsNullOrEmpty(userName))
throw new ArgumentNullException("userName");
if (string.IsNullOrEmpty(clientSecretJson))
throw new ArgumentNullException("clientSecretJson");
if (!File.Exists(clientSecretJson))
throw new Exception("clientSecretJson file does not exist.");
// These are the scopes of permissions you need. It is best to request only what you need and not all of them
string[] scopes = new string[] { DriveService.Scope.DriveReadonly}; //View the files in your Google Drive
UserCredential credential;
using (var stream = new FileStream(clientSecretJson, FileMode.Open, FileAccess.Read))
{
string credPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
credPath = Path.Combine(credPath, ".credentials/", System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
// Requesting Authentication or loading previously stored authentication for userName
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(stream).Secrets,
scopes,
userName,
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
}
// Create Drive API service.
return new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Drive Oauth2 Authentication Sample"
});
}
catch (Exception ex)
{
Console.WriteLine("Create Oauth2 account DriveService failed" + ex.Message);
throw new Exception("CreateServiceAccountDriveFailed", ex);
}
}
File.List
My tutorial on searching for files with the file.list method contains the code you will need to list files. I wont be adding that here i recommend you check out that tutorial first. Search files with Google Drive with C#.
[wp_ad_camp_3]
Download File
Downloading a file is done with the Files.get method and a media downloader from the client library to download your file.
private static void DownloadFile(Google.Apis.Drive.v3.DriveService service, Google.Apis.Drive.v3.Data.File file, string saveTo)
{
var request = service.Files.Get(file.Id);
var stream = new System.IO.MemoryStream();
// Add a handler which will be notified on progress changes.
// It will notify on each chunk download and when the
// download is completed or failed.
request.MediaDownloader.ProgressChanged += (Google.Apis.Download.IDownloadProgress progress) =>
{
switch (progress.Status)
{
case Google.Apis.Download.DownloadStatus.Downloading:
{
Console.WriteLine(progress.BytesDownloaded);
break;
}
case Google.Apis.Download.DownloadStatus.Completed:
{
Console.WriteLine("Download complete.");
SaveStream(stream, saveTo);
break;
}
case Google.Apis.Download.DownloadStatus.Failed:
{
Console.WriteLine("Download failed.");
break;
}
}
};
request.Download(stream);
}
Assuming that the file download succeeds then we save the file to the hard drive.
private static void SaveStream(System.IO.MemoryStream stream, string saveTo)
{
using (System.IO.FileStream file = new System.IO.FileStream(saveTo, System.IO.FileMode.Create, System.IO.FileAccess.Write))
{
stream.WriteTo(file);
}
}
[wp_ad_camp_5]
Putting it all together
By using file.list I can search for the files that I am interested in then loop though each one downloading it.
// Connect to Google
var service = GoogleSamplecSharpSample.Drivev3.Auth.Oauth2Example.AuthenticateOauth(@"[Location of the Json cred file]", "test");
// the files with the word 'make' in the name.
var files = DriveListExample.ListFiles(service,
new DriveListExample.FilesListOptionalParms() { Q = "name contains 'Make'" , Fields= "*"});
foreach (var item in files.Files)
{
// download each file
DriveDownload.Download(service, item, string.Format(@"C:\FilesFromGoogleDrive\{0}",item.Name));
}
Conclusion
Downloading files from Google drive can be quite useful using media downloader makes it quite simple. I have considered setting up a windows service to mirror my google drive account down to my PC and back up to Google Drive. This way i can keep the data backed up and in sync.
hi Linda thanks for the snippet code .i had an error in the path where to save its gave me a denied access to these path
I would make sure that what ever user you are running the code as has access to the path you are trying to save to.
Hello Linda, how can I do the same, download files but, from mvc asp.net ??
The only difference will be how you authenticate. try following this https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth#web-applications-aspnet-mvc
Hello Linda!
How does this work with the file.export method? I used: var request = service.Files.Export(fileId, “application/vnd.openxmlformats-officedocument.spreadsheetml.sheet”);. Shouldnt the file get an extension by itsfel then or am I mistaken?
No i dont think google is going to set the extension for you.
Hello Linda, its been a while but today I noticed a problem. When downloading larger files (well 80MB>, isnt that large) the downlaod wont complete correctly. I tested it with several zip files: 100mb, 200mb, 512mb and 1gb. 100mb and 200mb just work fine but the other two dont. When trying to download the 512mb zip file it stops at about 320 000 000 bytes, writes “Downlaod complete” in the console and goes on to the next file. Obviously the file didnt get saved on my HDD.
Do you have any clue what could be causing this?
You will probably need to add multi part resumable download i havent had time to add that to this tutorial.
Actually the problem is a bit different now. I didn’t change much in my code but for now this works, except files that are larger than 2GB (stops at about 2040MB). I read that this seems to be a common issue because this is a limitation at googles site, right? There must be a way to bypass that, except for installing the desktop app.
I am not sure if its a limitation but its something i have heard of. The Google drive api doesn’t appear to like large files. Make sure you are using resumable download or upload then you can pick up where it failed.
Hi,
I have written a code to Upload and Download files using from Google Drive.
It is working very fine in Local, but when I deploy it on Server it is giving error in Download part where we use “GoogleWebAuthorizationBroker.AuthorizeAsync” method to get Service credentials. It gives following error
“Server Error in ‘/’ Application.
________________________________________
Access is denied
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ComponentModel.Win32Exception: Access is denied
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Stack Trace:
[Win32Exception (0x80004005): Access is denied]
Microsoft.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +185
Microsoft.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccess(Task task) +114
Google.Apis.Auth.OAuth2.d__1.MoveNext() +483
[AggregateException: One or more errors occurred.]
System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification) +5836036
GoogleDriveRestAPI_v3.Models.GoogleDriveFilesRepository.GetService() +467
GoogleDriveRestAPI_v3.Models.GoogleDriveFilesRepository.DownloadGoogleFile(String fileId) +35
GoogleDriveRestAPI_v3.Controllers.HomeController.DownloadFile(String id) +356
System.Web.Mvc.c__DisplayClass1.b__0(ControllerBase controller, Object[] parameters) +15
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +242
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +39
System.Web.Mvc.Async.AsyncControllerActionInvoker.b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState) +12
System.Web.Mvc.Async.WrappedAsyncResult`2.CallEndDelegate(IAsyncResult asyncResult) +139
System.Web.Mvc.Async.AsyncInvocationWithFilters.b__3d() +112
System.Web.Mvc.Async.c__DisplayClass46.b__3f() +452
System.Web.Mvc.Async.c__DisplayClass33.b__32(IAsyncResult asyncResult) +15
System.Web.Mvc.Async.c__DisplayClass2b.b__1c() +37
System.Web.Mvc.Async.c__DisplayClass21.b__1e(IAsyncResult asyncResult) +241
System.Web.Mvc.Controller.b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +29
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +111
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +53
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +19
System.Web.Mvc.MvcHandler.b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +51
System.Web.Mvc.Async.WrappedAsyncVoid`1.CallEndDelegate(IAsyncResult asyncResult) +111
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +606
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +288
________________________________________
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.33440”
Due to this error TokenResponse file is not getting created using following code
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
“user”,
CancellationToken.None,
new FileDataStore(FilePath, true)
).Result;
Please suggest solution so that this code works on Server after deploying in IIS.
You apear to be using the code for installed applications you should be using the code for web applications
Hi, thanks for your reply. I am using installed application code because I do not want user to login while downloading file.In the link you suggested it asks user to login to Gmail for authorization.
A user will always have to be logged in to access their data. Unless you are trying to access your own data and then you should be using a service account.
Great explanation – very useful for beginners!
Hi,
Is that possible to download file from Shared link in a google drive without user credentials ?
for example in my google drive i have a text file
i get that text file shared link(Get shareable link) and send to customer who is using my .net application
can he download the text file through the shared link without credentials?…
Thanks for understanding
maybe if the file is public but i am not sure that works anymore.
Is it possible to download files synchronously? I like the event-driven approach you describe, but synchronous is better suited to my application.
You will have to check the library see what methods are available.
hi,
i have tried same code to download csv files from google folder,So It is asking me to authenticate and then i am able to download.
but when it comes to VM i published code and Hosted in IIS.and it is not asking me to Authenticate.
more over i am not getting error So i am Not Understanding What’s Happening In VM.
Thats because it already has your authorization stored in credPath = Path.Combine(credPath, “.credentials/”, System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
Linda Does Above Code Work To Download Files from google folder using service account
The authorization method in this sample is for installed applications only. The code to authorize a service account would be different.