'Why is my UpdateFile getting a null in the response in google drive api v3 using c#?

I have an application that is written in C# so that it can be a stand-alone .exe with parameters passed in via cmd at runtime. I am trying to update a file in google drive without changing the fileid so that any links using that id will not be broken. The following code works until it gets to the third section using Google.Apis.Drive.v3.Data.File updateFile in which the file is always 'null'. The request.ResponseBody has the correct fileId, the correct path and all but always comes up null.

How can I get this to update a file?

Is there some code update/change that no longer works?

Any help would be appreciated-

Section 1- This is the start of the code that calls the next two sections:

    // System Library Requirements
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections.ObjectModel;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Security;
// Microsoft Library Requirements
using Microsoft.Win32;
// Google API Library Requirements
using Google.Apis.Gmail.v1;
using Google.Apis.Gmail.v1.Data;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Drive.v3;
using GoogleV2 = Google.Apis.Drive.v2;
using Google.Apis.Drive.v3.Data;

using GoogleV2data = Google.Apis.Drive.v2.Data;
using Google.Apis.Services;
using Google.Apis.Util.Store;
using Google.Apis.Requests;
using Google.Apis.Auth.OAuth2.Responses;
using Google.Api.Gax;
using Google.Cloud.Channel.V1;
// JSON reading/serializing/De-serializing Library Requirements
using Newtonsoft.Json;
// Mime-Type Library Requirements
using MimeKit;
using Google.Apis.Upload;
// CyberArk Library Requirements
using CyberArk.AIM.NetPasswordSDK;
using CyberArk.AIM.NetPasswordSDK.Exceptions;



static class Globals
{
    //cyberark values will change based on the domain and the app and the safe
    public static string google_client_secret;
    public static string cyberark_client_id = "...xxxx.....apps.googleusercontent.com";
    public static string cyberark_object = "...xxx...";
    public static string cyberark_app_id = "...xxx...";
    public static string cyberark_safe = "...xxx...";
    //google app values will change based on the domain and gcp project information e.g. np vs prod
    public static string google_app_name = "my_google_app_name";
    public static string google_client_id = "my_google_client_id";
    public static string google_data_store = "my_google_data_store";

    

}

class Program
{
    static void Main(string[] args)
    {


        Globals.google_client_secret = NetPasswordSDK.CyberArkProgram.GetMyPassword(NetPasswordSDK.MyCredentials.MY_APP_ID, NetPasswordSDK.MyCredentials.MY_SAFE, NetPasswordSDK.MyCredentials.MY_OBJECT, NetPasswordSDK.MyCredentials.MY_SECURE_STRING);

        var paramFolderID = "";
        var paramDriveFromFolderName = "";
        var paramUserID = "";
        var paramTeamID = "";
        var paramFileName = "";
        var paramFilePath = "";
        var paramLocalFolderPath = "";


        if (args == null || args.Length == 0)
        {
            Console.WriteLine("No Arguments passed");
        }
        else
        {
            paramFolderID = args[0];
            paramDriveFromFolderName = args[1];
            paramUserID = args[2];
            paramTeamID = args[3];
            paramFileName = args[4];
            paramFilePath = args[5];
            paramLocalFolderPath = args[6];



            Console.WriteLine("FolderID " + args[0]);
            Console.WriteLine("DriveFromFolderName " + args[1]);
            Console.WriteLine("UserID " + args[2]);
            Console.WriteLine("TeamID " + args[3]);
            Console.WriteLine("FileName " + args[4]);
            Console.WriteLine("FilePath " + args[5]);
            Console.WriteLine("LocalFolderPath " + args[6]);

        }

        string googleUpdateText = "";
        string googleUpdateFilePath = "";
        string googleUpdateLocalFolderPath = "";
        string googleUpdateFileName = "";
        string googleUpdateParentFolder = "";
        string googleUpdateTeamDriveID = "";
        string googleUpdateParentFolderID = "";


        var proxy = WebRequest.DefaultWebProxy;
        proxy.Credentials = CredentialCache.DefaultCredentials;
        var httpClientHandler = new HttpClientHandler()
        {
            Proxy = proxy
        };


        {


            {



                //googleUpdateParentFolderID = paramFolderID;
                //googleUpdateParentFolder = paramDriveFromFolderName;
                //googleUpdateTeamDriveID = paramTeamID;
                //googleUpdateFileName = paramFileName;
                //googleUpdateFilePath = paramFilePath;
                //googleUpdateLocalFolderPath = paramLocalFolderPath;

                // HC values for testing
                googleUpdateFilePath = "C:\\Path\\to_update_file\\update_file.txt";
                googleUpdateLocalFolderPath = "C:\\Path\\to_update_file\\";
                googleUpdateFileName = "update_file.txt";
                googleUpdateParentFolder = "Folder_on_Google_Drive";
                googleUpdateTeamDriveID = "Team_Drive_ID";
                googleUpdateParentFolderID = "Parent_Folder_ID";


                Console.WriteLine("value of   googleUploadFilePath: " + googleUpdateFilePath);
                Console.WriteLine("value of   googleUploadLocalFolderPath: " + googleUpdateLocalFolderPath);
                Console.WriteLine("value of   googleUploadFileName: " + googleUpdateFileName);
                Console.WriteLine("value of   googleUploadParentFolder: " + googleUpdateParentFolder);
                Console.WriteLine("value of   googleUploadTeamDriveID: " + googleUpdateTeamDriveID);
                Console.WriteLine("value of   googleUploadParentFolderID: " + googleUpdateParentFolderID);

                googleUpdateText = (JsonConvert.SerializeObject(GoogleAPI.GoogleAPI_Drive.GDrive_Update_File(googleUpdateFilePath, googleUpdateLocalFolderPath, googleUpdateFileName, "no description", googleUpdateParentFolder, paramUserID, "", "", googleUpdateTeamDriveID, googleUpdateParentFolderID), Formatting.Indented));

                Console.WriteLine("value of googleUpdateText: " + googleUpdateText);
                Console.WriteLine("this is the end of the update text");


                


            };


            // end 
        }

        // end of Main
    }

    // end of program class
}

Section 2- This is the middle part of the code that updates files in a list of files which calls each file to update it.

public static String GDrive_Update_File(string pathToFile, string localFilePath, string fileName, string description, string parentFolder = "", string userid = "", string sharedUserIds = "", string sharerole = "", string teamID = "", string parentFolderID = "")
{



    FileResponseJSON fileJson = new FileResponseJSON();

    List<string> fileArray = new List<string> { };
    IList<FileResponseJSON> filesJSON = new List<FileResponseJSON>();
    IList<Google.Apis.Drive.v3.Data.File> files = new List<Google.Apis.Drive.v3.Data.File>();


    List<string> parents = new List<String> { };
    List<string> kids = new List<String> { };

    UserCredential credential = GoogleAPI_Functions.GetCredentials(userid);
    var service = new DriveService(new BaseClientService.Initializer
    {
        ApplicationName = APP_NAME,
        HttpClientInitializer = credential,
    });

    if (!String.IsNullOrEmpty(parentFolder))
    {
        FilesResource.ListRequest listRequest = service.Files.List();
        listRequest.Q = String.Format("(name contains '{0}') and (mimeType = 'application/vnd.google-apps.folder')", parentFolder);
        listRequest.Fields = "files(*)";


        if (teamID.Length > 3)
        {
            listRequest.SupportsTeamDrives = true;  // new 
            listRequest.Corpora = "teamDrive";  // new 
            listRequest.IncludeTeamDriveItems = true;//new
            listRequest.TeamDriveId = teamID;//new




        }

        // List files.
        IList<Google.Apis.Drive.v3.Data.File> folders = listRequest.Execute().Files;


        foreach (var fldr in folders)
        {


            if (parentFolderID.Length > 3)
            {
                if (fldr.Id.Equals(parentFolderID))
                {
                    parents.Add(fldr.Id);


                }
            }
            else
            {
                parents.Add(fldr.Id);

            }

            Console.WriteLine("value of fldr.Id " + fldr.Id);
        }


    }

    // Upload File MetaData

    // mimeType is important and so it the 'trashed' true/false or it won't be found
    FilesResource.ListRequest fileRequest = service.Files.List();
    string query = "name contains 'update_file.txt' and (mimeType = 'text/plain') and trashed = false";
    fileRequest.Q = String.Format(query);
    fileRequest.Fields = "files(*)";

    fileRequest.SupportsTeamDrives = true;  // new 
    fileRequest.Corpora = "teamDrive";  // new 
    fileRequest.IncludeTeamDriveItems = true;//new
    fileRequest.TeamDriveId = teamID;//new

    IList<Google.Apis.Drive.v3.Data.File> myFiles = fileRequest.Execute().Files;

    Console.WriteLine("Files:");
    if (myFiles != null && myFiles.Count > 0)
    {
        foreach (var myf in myFiles)
        {
            myf.Name = localFilePath + myf.Name;

            Console.WriteLine("{0} ({1})", myf.Name, myf.Id);
            UpdateFile(service, myf.Name, myf.Id);
        }
    }
    else
    {
        Console.WriteLine("No files found.");
    }
    Console.Read();


    var UpdatedID = "";




    return UpdatedID;
}

Section 3- This section is supposed to update each file --> THIS IS THE SECTION WITH THE PROBLEM (The Google.Apis.Drive.v3.Data.File updatedFile always returns null)

        public static Google.Apis.Drive.v3.Data.File UpdateFile(DriveService _service, string _uploadFile, string _fileId)
    {
        
        Google.Apis.Drive.v3.Data.File file = new Google.Apis.Drive.v3.Data.File();
        byte[] byteArray = System.IO.File.ReadAllBytes(_uploadFile);
        System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);
        FilesResource.UpdateMediaUpload request = _service.Files.Update(file, _fileId, stream, GetMimeType(_uploadFile));

        void Upload_ProgressChanged(IUploadProgress progress) =>
        Console.WriteLine(progress.Status + " " + progress.BytesSent);

        void Upload_ResponseReceived(Google.Apis.Drive.v3.Data.File myfile) =>
        Console.WriteLine(myfile.Name + " was uploaded successfully");

        request.ProgressChanged += Upload_ProgressChanged;
        request.ResponseReceived += Upload_ResponseReceived;

        request.Upload();
        Google.Apis.Drive.v3.Data.File updatedFile = request.ResponseBody;
        return updatedFile;



    }

update: I used IUploadProgress.Exception and got the following error-

Exception: The service drive has thrown an exception: Google.GoogleApiException: Google.Apis.Requests.RequestError
File not found: 1XYZ..... [404]
Errors [
        Message[File not found: 1XYZ.......] Location[fileId - parameter] Reason[notFound] Domain[global]
]
   at Google.Apis.Upload.ResumableUpload.<HandleResponse>d__78.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Google.Apis.Upload.ResumableUpload.<SendNextChunkAsync>d__77.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Google.Apis.Upload.ResumableUpload.<UploadCoreAsync>d__74.MoveNext() 0

Update again, I was able to see the uri that was being generated and copy/paste it into the browser, and when I did I got a 405 Method Not Allowed; additionally when I tried it without the https and just used http I got a 403 Forbidden and that SSL is required to perform this operation

This is the uri without the ids https://www.googleapis.com/upload/drive/v3/files/[file_id]?uploadType=resumable&upload_id=[upload_id]

Update: During the process the api produces these two urls that both work and allow me access

WebContentLink

"https://drive.google.com/uc?id=[docID]&export=download"

WebViewLink

"https://drive.google.com/file/d/[docID]/view?usp=drivesdk"

Latest update applied fixes from DalmTo but am getting new errors-

// - removed // Google.Apis.Drive.v3.Data.File file = new 

// - added //

            var fileMetadata = new Google.Apis.Drive.v3.Data.File()
            {
                Id = _fileId
            };

            var fsSource = new MemoryStream(Encoding.UTF8.GetBytes(_uploadFile ?? ""));

            var request = _service.Files.Update(fileMetadata, fileMetadata.Id, fsSource, GetMimeType(_uploadFile));

New error:

Exception: The service drive has thrown an exception: Google.GoogleApiException: Google.Apis.Requests.RequestError
The resource body includes fields which are not directly writable. [403]
Errors [
        Message[The resource body includes fields which are not directly writable.] Location[ - ] Reason[fieldNotWritable] Domain[global]
]

Not sure what would cause this.



Solution 1:[1]

File id is writeable so you should be able to send it with the file metadata in your request.

var fileMetadata  = new Google.Apis.Drive.v3.Data.File()
{
    Id = "xxx" 
};

var fsSource = new MemoryStream(Encoding.UTF8.GetBytes(uploadString ?? ""));
var  request = service.Files.Update(fileMetadata, fileMetadata.Id , fsSource, GetMimeType(uploadFilePath));

Update

From comments you are sending an empty metadata file object with your request.

Google.Apis.Drive.v3.Data.File file = new Google.Apis.Drive.v3.Data.File();

There for Drive is always going to give you a new file id. I am sending the original file id as part of the metadata there for it will use the file id.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1