title: C# - upload files to Google Drive (Google Drive API)
body: <p>I am building a desktop app (WinForms) in C# (VS 2019, .net Framework 4.7.2) which allows the user to select a file, then does some processing on the file, then uploads the file to a Google Drive account and provides the user a direct download link to the file.</p>
  
  <p>I have been testing various sample code found on <a href="https://developers.google.com/drive/api/v3/manage-uploads#use_a_pregenerated_id_to_upload_files" rel="nofollow noreferrer">Google's API docs</a>, <a href="https://stackoverflow.com/questions/37265379/google-drive-net-sdk-version-3-shareable-links">StackOverflow</a>, and <a href="https://www.daimto.com/google-drive-api-c-upload/" rel="nofollow noreferrer">other</a> <a href="https://www.c-sharpcorner.com/article/how-to-upload-a-file-to-google-drive-using-google-api-from-net/" rel="nofollow noreferrer">sites</a>.</p>
  
  <p>It seems there is a mishmash of V2 and V3 API examples, and I have not yet found a clear example using V3.</p>
  
  <p>I have sort of gotten it to work with the code below, cobbled together from various sources, but there are a few problems:</p>
  
  <ol>
  <li><p>Larger files don't work (tested 30MB file and nothing happens - no
  definitive error messages).  I need to support files at least 100MB in size.</p></li>
  <li><p>Every upload throws exceptions, even if the upload completes successfully. (See console output below)</p></li>
  <li><p>The Progress function does not get called periodically through the upload, so I don't get regular progress updates (i.e. the app just sits there until the
  upload is done, with no report on progress.)</p></li>
  </ol>
  
  <p>I'm seeking a complete code snippet to perform a Google Drive upload which:</p>
  
  <ol>
  <li>Includes the Authentication steps</li>
  <li>Is written using the V3 API</li>
  <li>Allows the upload of large files (100+ MB)</li>
  <li>Provides progress feedback</li>
  <li>Provides clear success/failure feedback (doesn't throw exceptions unless a failure occurs)</li>
  <li>Returns a public shareable link to the uploaded file (i.e. a link that doesn't require the recipient to log into Google in order to download the file)</li>
  </ol>
  
  <p>Here is what I have so far:</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Data;
  using System.Drawing;
  using System.Linq;
  using System.Text;
  using System.Threading;
  using System.Threading.Tasks;
  using System.Windows.Forms;
  using Google.Apis;
  using Google.Apis.Auth;
  using Google.Apis.Auth.OAuth2;
  using Google.Apis.Drive.v3;
  using Google.Apis.Services;
  using Google.Apis.Util.Store;
  
  namespace FileUploader
  {
      public partial class Form2 : Form
      {
  
          private DriveService service;
  
          public Form2()
          {
              InitializeComponent();
          }
  
          private void btnAuth_Click(object sender, EventArgs e)
          {
  
              string[] scopes = new string[] { DriveService.Scope.Drive,
                                  DriveService.Scope.DriveFile,};
  
              var clientId = "******.apps.googleusercontent.com";      // From https://console.developers.google.com  
              var clientSecret = "******";          // From https://console.developers.google.com  
  
              // here is where we Request the user to give us access, or use the Refresh Token that was previously stored in %AppData%  
              var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets
              {
                  ClientId = clientId,
                  ClientSecret = clientSecret
              }, scopes,
              Environment.UserName, CancellationToken.None, new FileDataStore("UploaderToken")).Result;
              //Once consent is recieved, your token will be stored locally on the AppData directory, so that next time you wont be prompted for consent.   
  
              service = new DriveService(new BaseClientService.Initializer()
              {
                  HttpClientInitializer = credential,
                  ApplicationName = "UploaderApp",
  
              });
              service.HttpClient.Timeout = TimeSpan.FromMinutes(100);
              //Long Operations like file uploads might timeout. 100 is just precautionary value, can be set to any reasonable value depending on what you use your service for  
  
  
  
              var response = uploadFile(service, txtUpload.Text, "");
              // Third parameter is empty it means it would upload to root directory, if you want to upload under a folder, pass folder's id here.
              //MessageBox.Show("Process completed--- Response--" + response);
              Console.WriteLine("Completed: " + response);
  
          }
  
  
  
          public Google.Apis.Drive.v3.Data.File uploadFile(DriveService _service, string _uploadFile, string _parent, string _descrp = "Uploaded with .NET!")
          {
              if (System.IO.File.Exists(_uploadFile))
              {
                  Google.Apis.Drive.v3.Data.File body = new Google.Apis.Drive.v3.Data.File();
                  body.Name = System.IO.Path.GetFileName(_uploadFile);
                  body.Description = _descrp;
                  body.MimeType = GetMimeType(_uploadFile);
                  // body.Parents = new List&lt;string&gt; { _parent };// UN comment if you want to upload to a folder(ID of parent folder need to be send as paramter in above method)
                  byte[] byteArray = System.IO.File.ReadAllBytes(_uploadFile);
                  System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);
                  try
                  {
                      FilesResource.CreateMediaUpload request = _service.Files.Create(body, stream, GetMimeType(_uploadFile));
                      //request.SupportsTeamDrives = true;
                      // You can bind event handler with progress changed event and response recieved(completed event)
                      request.ProgressChanged += Request_ProgressChanged;
                      request.ResponseReceived += Request_ResponseReceived;
                      request.UploadAsync();
                      return request.ResponseBody;
                  }
                  catch (Exception e)
                  {
                      Console.WriteLine("Error: " + e.Message);
                      return null;
                  }
              }
              else
              {
                  MessageBox.Show("The file does not exist.", "404");
                  return null;
              }
          }
  
          private static string GetMimeType(string fileName)
          {
              string mimeType = "application/unknown";
              string ext = System.IO.Path.GetExtension(fileName).ToLower();
              Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext);
              if (regKey != null &amp;&amp; regKey.GetValue("Content Type") != null)
                  mimeType = regKey.GetValue("Content Type").ToString();
              return mimeType;
          }
  
          private void Request_ProgressChanged(Google.Apis.Upload.IUploadProgress obj)
          {
              txtProgress.Text += obj.Status + " " + obj.BytesSent;
          }
  
          private void Request_ResponseReceived(Google.Apis.Drive.v3.Data.File obj)
          {
              if (obj != null)
              {
                  Console.WriteLine("File was uploaded sucessfully--" + obj.Id);
                  Console.WriteLine("Getting shareable link...");
  
                  // When completed, get shareable link:
                  string fileId = obj.Id;
                  Google.Apis.Drive.v3.Data.Permission permission = new Google.Apis.Drive.v3.Data.Permission();
                  permission.Type = "anyone";
                  permission.Role = "reader";
                  permission.AllowFileDiscovery = true;
  
                  PermissionsResource.CreateRequest request = service.Permissions.Create(permission, fileId);
                  try
                  {
                      request.Fields = "*";
                      request.Execute();
                  }
                  catch (Exception e)
                  {
                      Console.WriteLine("Exception: " + e.Message);
                  }
  
                  FilesResource.ListRequest listRequest = service.Files.List();
                  listRequest.Fields = "*";
  
                  List&lt;Google.Apis.Drive.v3.Data.File&gt; files;
                  Google.Apis.Drive.v3.Data.File myFile = null;
                  try
                  {
  
  
                      files = listRequest.Execute().Files.ToList();
                       myFile = files.Single(f =&gt; f.Id == fileId);
  
                  }
                  catch (Exception e)
                  {
                      Console.WriteLine("Exception2: " + e.Message);
                  }
  
  
                  string shareableLink = myFile.WebContentLink;
  
                  Console.WriteLine("Shareable link to file: " + shareableLink);
  
              }
          }
  
  
      }
  }
  </code></pre>
  
  <p>Console output:</p>
  
  <pre><code>Completed: 
  File was uploaded sucessfully--[file ID here]
  Getting shareable link...
  Shareable link to file: https://drive.google.com/a/*******&amp;export=download
  Exception thrown: 'System.InvalidOperationException' in System.Windows.Forms.dll
  Exception thrown: 'System.InvalidOperationException' in System.Windows.Forms.dll
  Exception thrown: 'System.InvalidOperationException' in mscorlib.dll
  The thread 0x3d68 has exited with code 0 (0x0).
  The thread 0x3d58 has exited with code 0 (0x0).
  The thread 0x3d88 has exited with code 0 (0x0).
  The thread 0x3d48 has exited with code 0 (0x0).
  The thread 0x3d44 has exited with code 0 (0x0).
  </code></pre>