为什么我的 UpdateFile 在使用 C# 的 google Drive api v3 中的响应中得到空值?

ASh*_*ork 5 c# google-api google-drive-api google-api-dotnet-client

我有一个用 C# 编写的应用程序,因此它可以是一个独立的 .exe,并在运行时通过 cmd 传入参数。我正在尝试更新 google 驱动器中的文件而不更改 fileid,以便使用该 id 的任何链接都不会被破坏。以下代码一直有效,直到使用 Google.Apis.Drive.v3.Data.File updateFile 到达第三部分,其中文件始终为“null”。request.ResponseBody 具有正确的 fileId、正确的路径,并且几乎总是出现空值。

我怎样才能得到它来更新文件?

是否有一些代码更新/更改不再有效?

任何帮助,将不胜感激-

第 1 部分 - 这是调用接下来两部分的代码的开头:

    // 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
}
Run Code Online (Sandbox Code Playgroud)

第 2 部分 - 这是更新文件列表中的文件的代码的中间部分,该列表调用每个文件来更新它。

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;
}
Run Code Online (Sandbox Code Playgroud)

第 3 节 - 本节应该更新每个文件 --> 这是有问题的部分(Google.Apis.Drive.v3.Data.File UpdatedFile 始终返回 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;



    }
Run Code Online (Sandbox Code Playgroud)

更新:我使用 IUploadProgress.Exception 并收到以下错误 -

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
Run Code Online (Sandbox Code Playgroud)

再次更新,我能够看到正在生成的 uri 并将其复制/粘贴到浏览器中,当我这样做时,我得到了 405 Method Not allowed; 另外,当我在没有 https 的情况下尝试使用 http 时,我得到了 403 Forbidden,并且需要 SSL 才能执行此操作

这是没有 id 的 uri https://www.googleapis.com/upload/drive/v3/files/[file_id]?uploadType=resumable&upload_id=[upload_id]

更新:在此过程中,api 生成这两个 url,它们都可以工作并允许我访问

网页内容链接

"https://drive.google.com/uc?id=[docID]&export=download"
Run Code Online (Sandbox Code Playgroud)

网页浏览链接

"https://drive.google.com/file/d/[docID]/view?usp=drivesdk"
Run Code Online (Sandbox Code Playgroud)

最新更新应用了 DalmTo 的修复,但收到新错误 -

// - 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));
Run Code Online (Sandbox Code Playgroud)

新错误:

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]
]
Run Code Online (Sandbox Code Playgroud)

不知道什么会导致这种情况。

DaI*_*mTo 2

文件 ID 是可写的,因此您应该能够将其与请求中的文件元数据一起发送。

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));
Run Code Online (Sandbox Code Playgroud)

更新

根据评论,您将随您的请求发送一个空的元数据文件对象。

Google.Apis.Drive.v3.Data.File file = new Google.Apis.Drive.v3.Data.File();
Run Code Online (Sandbox Code Playgroud)

Drive 总是会给你一个新的文件 ID。我将原始文件 ID 作为元数据的一部分发送到那里,因为它将使用该文件 ID。