0

I am trying download file from google drive using the code below:

     public static Boolean downloadFile(string downloadurl, string _saveTo)
        {

            if (!String.IsNullOrEmpty(downloadurl))
            {
                try
                {
                  var x = service.HttpClient.GetByteArrayAsync(downloadurl);
                    byte[] arrBytes = x.Result;
                    System.IO.File.WriteAllBytes(_saveTo, arrBytes);
                    return true;
                }
                catch (Exception e)
                {
                    Console.WriteLine("An error occurred: " + e.Message);
                    return false;
                }
            }
            else
            {
                // The file doesn't have any content stored on Drive.
                return false;
            }
        }

On debugging the above code throwing exception as below:

?service.HttpClient.GetByteArrayAsync(downloadurl)
Id = 10, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}"
    AsyncState: null
    CancellationPending: false
    CreationOptions: None
    Exception: null
    Id: 10
    Result: null
    Status: WaitingForActivation

I am trying to do it from my Service account created using Google API Console.

and the exception detail is as follows:

System.NullReferenceException was caught
  HResult=-2147467261
  Message=Object reference not set to an instance of an object.
  Source=System.Net.Http
  StackTrace:
       at System.Net.Http.Headers.HttpRequestHeaders.AddHeaders(HttpHeaders sourceHeaders)
       at System.Net.Http.HttpClient.PrepareRequestMessage(HttpRequestMessage request)
       at System.Net.Http.HttpClient.SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
       at System.Net.Http.HttpClient.GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken)
       at System.Net.Http.HttpClient.GetContentAsync[T](Uri requestUri, HttpCompletionOption completionOption, T defaultValue, Func`2 readAs)
       at System.Net.Http.HttpClient.GetByteArrayAsync(Uri requestUri)
       at System.Net.Http.HttpClient.GetByteArrayAsync(String requestUri)
Yogesh Aswani
  • 43
  • 3
  • 10

2 Answers2

1

You can try this.
link

using Google.Apis.Authentication;
    using Google.Apis.Drive.v2;
    using Google.Apis.Drive.v2.Data;

    using System.Net;

    public class MyClass {

      public static System.IO.Stream DownloadFile(
          IAuthenticator authenticator, File file) {
        if (!String.IsNullOrEmpty(file.DownloadUrl)) {
          try {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(
                new Uri(file.DownloadUrl));
            authenticator.ApplyAuthenticationToRequest(request);
            HttpWebResponse response = (HttpWebResponse) request.GetResponse();
            if (response.StatusCode == HttpStatusCode.OK) {
              return response.GetResponseStream();
            } else {
              Console.WriteLine(
                  "An error occurred: " + response.StatusDescription);
              return null;
            }
          } catch (Exception e) {
            Console.WriteLine("An error occurred: " + e.Message);
            return null;
          }
        } else {
          // The file doesn't have any content stored on Drive.
          return null;
        }
      }
    }
Dragon
  • 1,078
  • 2
  • 9
  • 31
  • how can I pass authenticator parameter as i am using service account which needs service email id only to activate the service only – Yogesh Aswani Aug 26 '15 at 07:30
  • For this case, I have given a link. – Dragon Aug 26 '15 at 07:37
  • Hi, we have gone through the link, but we have not found IAuthenticator interface in that code. I hope the same is required Access Token, refresh token which we don't have in case of service account. – Yogesh Aswani Aug 26 '15 at 08:02
0

Code using the Google .net client library

Service account:

string[] scopes = new string[] {DriveService.Scope.Drive}; // Full access

var keyFilePath = @"c:\file.p12" ;    // Downloaded from https://console.developers.google.com
var serviceAccountEmail = "xx@developer.gserviceaccount.com";  // found https://console.developers.google.com

//loading the Key file
var certificate = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);
var credential = new ServiceAccountCredential( new ServiceAccountCredential.Initializer(serviceAccountEmail) {
                                                   Scopes = scopes}.FromCertificate(certificate));

create drive service

var service = new DriveService(new BaseClientService.Initializer() {HttpClientInitializer = credential,
                                                                            ApplicationName = "Drive API Sample",});

You can use files.list to list all of the files on drive.

FilesResource.ListRequest request = service.Files.List();
request.Q = "trashed=false";
title = 'hello'
FileList files = request.Execute();

loop though the items returned find the file you want it is a file resource you can pass it to the following method to down load your file

/// <summary>
        /// Download a file
        /// Documentation: https://developers.google.com/drive/v2/reference/files/get
        /// </summary>
        /// <param name="_service">a Valid authenticated DriveService</param>
        /// <param name="_fileResource">File resource of the file to download</param>
        /// <param name="_saveTo">location of where to save the file including the file name to save it as.</param>
        /// <returns></returns>
        public static Boolean downloadFile(DriveService _service, File _fileResource, string _saveTo)
        {

            if (!String.IsNullOrEmpty(_fileResource.DownloadUrl))
            {
                try
                {
                    var x = _service.HttpClient.GetByteArrayAsync(_fileResource.DownloadUrl );
                    byte[] arrBytes = x.Result;
                    System.IO.File.WriteAllBytes(_saveTo, arrBytes);
                    return true;                  
                }
                catch (Exception e)
                {
                    Console.WriteLine("An error occurred: " + e.Message);
                    return false;
                }
            }
            else
            {
                // The file doesn't have any content stored on Drive.
                return false;
            }
        }

code ripped from Google drive authentication C#

Linda Lawton - DaImTo
  • 106,405
  • 32
  • 180
  • 449
  • We are doing this all from the code you have suggested us, we are not looping through the files, instead have stored the downloadurl in the database at the time the file was uploaded and simply passing the string instead of _fileResource.DownloadUrl. Rest all is exactly same as you suggested. – Yogesh Aswani Aug 26 '15 at 09:43
  • Glad it worked :) Just watch the download url I have a strange recollection of it changing sometimes if someone updates it on drive. – Linda Lawton - DaImTo Aug 26 '15 at 09:44
  • One more clarification though, as we used this code to get the file _fileResource = GetFileByID(fileid, service); and then used this code to get download url _fileResource.DownloadUrl but unfortunately it returned null value so we have changed the stance from this to already available file download url. – Yogesh Aswani Aug 26 '15 at 10:08
  • File file = service.Files.Get(fileId).Execute(); should return the download link as well I find it strange that its not. – Linda Lawton - DaImTo Aug 26 '15 at 11:18
  • Is there anything that I can check in my Google Drive account, or anything to be done with service email. I have created new email and new service account, I am afraid if there is any restriction from google. – Yogesh Aswani Aug 26 '15 at 12:41
  • Well a service account won't have access unless you give it access – Linda Lawton - DaImTo Aug 26 '15 at 14:01
  • Access is already given for particular folder which is going to contain the files, also the files that are uploaded from service account have sufficient privileges. We are running it from localhost, is there any issue with it? – Yogesh Aswani Aug 26 '15 at 14:04
  • Hi @daimto , do we need to wait? – Yogesh Aswani Aug 27 '15 at 05:36
  • Is the service account downloading the file? – Linda Lawton - DaImTo Aug 27 '15 at 05:41
  • Hi, the downloadurl is started working now, we have deleted the files and uploaded fresh again and it is working. But back to our question `?service.HttpClient.GetByteArrayAsync(downloadurl)` throws exception and this is what we get in immediate window: `Id = 10, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}" AsyncState: null CancellationPending: false CreationOptions: None Exception: null Id: 10 Result: null Status: WaitingForActivation` – Yogesh Aswani Aug 27 '15 at 06:21
  • we have tried various combinations to get it done but we are not able to get it through – Yogesh Aswani Aug 27 '15 at 11:22
  • we have edited the question and put exception details for you to understand. – Yogesh Aswani Aug 27 '15 at 11:40