Google Drive API V3更新:没有例外,但不会更新

问题描述 投票:0回答:1

我正在尝试使用以下代码更新Google云端硬盘上的文件:

private async Task UpdateFileAsync(string fullPath, IList<string> parents, string id)
{
    string mimeT = GetMimeType(fullPath);
    Google.Apis.Drive.v3.Data.File file = new Google.Apis.Drive.v3.Data.File();
    file.Name = System.IO.Path.GetFileName(fullPath);
    //file.MimeType = mimeT;
    //file.Parents = parents;

    //using (var fStream = new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true))
    //{
    //    byte[] byteArray = new byte[fStream.Length];
    byte[] byteArray = System.IO.File.ReadAllBytes(fullPath);
        //await fStream.ReadAsync(byteArray, 0, (int)fStream.Length);
        using (var stream = new MemoryStream(byteArray))
        {
            var request = _DriveService.Files.Update(file, id, stream, mimeT);// .Create(file, stream, mimeT);
            request.AddParents = string.Join(",", parents);
            var progress = await request.UploadAsync();
            if (progress.Exception != null)
                throw progress.Exception;
        }
    //}
}
private 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 && regKey.GetValue("Content Type") != null)
        mimeType = regKey.GetValue("Content Type").ToString();
    return mimeType;
}

我没有触及注释行,所以你可以看到我尝试了什么。该文件是我首先下载的XML女巫,获取IdParents,然后在本地修改,所以我想更新它。

本地路径fullPath预先来自FileInfo.GetFullPath(),我检查它是否存在,并且在运行时使用断点在本地正确更新。

正如你所看到的,首先我尝试直接在google MimeType对象中设置ParentsFile,然后我读到了不可写的字段,所以我删除了那部分代码。我也试过各种流,首先我只使用FileStream,然后我尝试了两种你在代码中看到的方式。

我已经检查了权限,但我把它们放在这里以防万一我忘了:

private readonly string[] Scopes = {
        SheetsService.Scope.Spreadsheets,
        DriveService.Scope.DriveFile,
        DriveService.Scope.Drive,
        DriveService.Scope.DriveAppdata,
        DriveService.Scope.DriveMetadata };
...
_Credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
    GoogleClientSecrets.Load(stream).Secrets,
    Scopes,
    "user",
    CancellationToken.None,
    new FileDataStore(credPath, true));

代码运行正常,progress.Exception始终为null,但文件未更新。我也可以毫无问题地下载和上传文件。

而且我很确定这是我忘记的一件小事,但似乎我似乎无法看到它。我不知道发生了什么。

.


编辑:正如DaImTo在评论中提出的那样,我试图通过这种方式观察上传的进度:

private async Task UpdateFileAsync(string fullPath, IList<string> parents, string id)
{
    try
    {
        string mimeT = GetMimeType(fullPath);
        Google.Apis.Drive.v3.Data.File file = new Google.Apis.Drive.v3.Data.File();
        file.Name = System.IO.Path.GetFileName(fullPath);
        //file.MimeType = mimeT;
        //file.Parents = parents;

        using (var fStream = new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true))
        {
            byte[] byteArray = new byte[fStream.Length];
            //byte[] byteArray = System.IO.File.ReadAllBytes(fullPath);
            await fStream.ReadAsync(byteArray, 0, (int)fStream.Length);
            using (var stream = new MemoryStream(byteArray))
            {
                var request = _DriveService.Files.Update(file, id, stream, mimeT);// .Create(file, stream, mimeT);
                request.AddParents = string.Join(",", parents);
                request.ProgressChanged += (Google.Apis.Upload.IUploadProgress prog) =>
                {
                    switch (prog.Status)
                    {
                        case Google.Apis.Upload.UploadStatus.Uploading:
                            {
                                var forget = Log.WriteAsync($"------------- Progreso subida: {prog.BytesSent.ToString()}");
                                break;
                            }
                        case Google.Apis.Upload.UploadStatus.Completed:
                            {
                                var forget = Log.WriteAsync("------------- Upload complete.");
                            //var memData = memStream.ToArray();
                            break;
                            }
                        case Google.Apis.Upload.UploadStatus.Failed:
                            {
                                var forget = Log.WriteAsync("------------- Upload failed.");
                                break;
                            }
                    }
                };
                request.ResponseReceived += (Google.Apis.Drive.v3.Data.File f) =>
                {
                    var forget = Log.WriteAsync($"------------- File uploaded succesfully: {f.Name}");
                };
                var progress = await request.UploadAsync();

                if (progress.Exception != null)
                    throw progress.Exception;
            }
        }
    }
    catch (Exception e)
    {
        e.ShowException();
    }
}

此外,当我序列化文件以上传并获取文件的本地路径时,此方法之前的方法:

private async Task SerializeAndUpdateDataFileAsync(DriveContaData data, CancellationToken cancelToken)
{
    var path = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, Properties.Settings.Default.DriveContaDataName);
    var tmp = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "tmp" + Properties.Settings.Default.DriveContaDataName);

    try
    {
        await SerializeDriveContaDataAsync(
                        tmp,
                        new SerializableProxy_DriveContaData(data));
        if (cancelToken.IsCancellationRequested)
            return;

        System.IO.File.Delete(path);
        System.IO.File.Move(tmp, path);
        await UpdateFileAsync(path, Properties.Settings.Default.MJContaFolderID.Cast<string>().ToList(), Properties.Settings.Default.DriveContaDataId);
        if (cancelToken.IsCancellationRequested)
            return;
        DataFileSavedAndUploaded = true;
    }
    catch (Exception e)
    {
        e.ShowException();
    }
}

日志显示File uploaded succesfullyUpload complete线。

.


Edit2:好的,我已经创建了一个新的,干净的项目,并复制/修改了代码以仅进行更新。相同的结果,本地文件是正确的,登录正确,权限更正,尝试更新驱动器上的文件没有任何反应:没有例外,没有更新。

这个类进行更新:

public class GoogleLogin
{
    public GoogleLogin() { _FilesLoader = new DriveFilesLoader(); }

    private const string ApplicationName = "DriveMJConta";
    private UserCredential _Credential;
    private SheetsService _SheetsService;
    private DriveService _DriveService;
    private DriveFilesLoader _FilesLoader;
    private readonly string[] Scopes = {
        SheetsService.Scope.Spreadsheets,
        DriveService.Scope.DriveFile,
        DriveService.Scope.Drive,
        DriveService.Scope.DriveAppdata,
        DriveService.Scope.DriveMetadata };
    private IList<string> _Parents;
    private string _Id;

    public bool IsSigned { get; private set; }

    private async Task SetMJContaAppFolderAsync()
    {
        var files = _FilesLoader.ListFiles(
                _DriveService,
                new DriveFilesLoader.FilesListOptionalParms()
                {
                    Q = @"name = '- DriveContaDataSave.xml' ",
                    Fields = "files(parents, id)"
                });
        _Parents = files.Files[0].Parents;
        _Id = files.Files[0].Id;
    }
    private 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 && regKey.GetValue("Content Type") != null)
            mimeType = regKey.GetValue("Content Type").ToString();
        return mimeType;
    }

    public async Task GetUserCredentialAsync()
    {
        //MessengerNSpace.Messenger.SendGuidedMessage("GOOGLELOGIN_START");
        try
        {
            var assembly = Assembly.GetExecutingAssembly();
            using (Stream stream = assembly.GetManifestResourceStream("PruebaGoogleDrive.Resources.client_secret.json"))
            {
                string credPath = System.Environment.GetFolderPath(
                    System.Environment.SpecialFolder.Personal);

                if (!IsSigned)
                {
                    _Credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
                        GoogleClientSecrets.Load(stream).Secrets,
                        Scopes,
                        "user",
                        CancellationToken.None,
                        new FileDataStore(credPath, true));
                    //Log.WriteAsync("Credential file saved to: " + credPath);
                }
                else
                {
                    await GoogleWebAuthorizationBroker.ReauthorizeAsync(
                        _Credential,
                        CancellationToken.None);
                    //Log.WriteAsync("Credential file saved to: " + credPath);
                }
            }

            _DriveService = new DriveService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = _Credential,
                ApplicationName = ApplicationName
            });

            await SetMJContaAppFolderAsync();
        }
        catch(Exception e)
        {
            e.ShowException();
        }

        MessageBox.Show("Login OK");
    }
    public async Task UpdateFileAsync(string fullPath)
    {
        try
        {
            string mimeT = GetMimeType(fullPath);
            Google.Apis.Drive.v3.Data.File file = new Google.Apis.Drive.v3.Data.File();
            file.Name = System.IO.Path.GetFileName(fullPath);
            //file.MimeType = mimeT;
            //file.Parents = parents;

            using (var fStream = new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true))
            {
                byte[] byteArray = new byte[fStream.Length];
                //byte[] byteArray = System.IO.File.ReadAllBytes(fullPath);
                await fStream.ReadAsync(byteArray, 0, (int)fStream.Length);
                using (var stream = new MemoryStream(byteArray))
                {
                    var request = _DriveService.Files.Update(file, _Id, stream, mimeT);// .Create(file, stream, mimeT);
                    request.AddParents = string.Join(",", _Parents);
                    request.ProgressChanged += (Google.Apis.Upload.IUploadProgress prog) =>
                    {
                        switch (prog.Status)
                        {
                            case Google.Apis.Upload.UploadStatus.Uploading:
                                {
                                    MessageBox.Show($"------------- Progreso subida: {prog.BytesSent.ToString()}");
                                    break;
                                }
                            case Google.Apis.Upload.UploadStatus.Completed:
                                {
                                    MessageBox.Show("------------- Upload complete.");
                                    //var memData = memStream.ToArray();
                                    break;
                                }
                            case Google.Apis.Upload.UploadStatus.Failed:
                                {
                                    MessageBox.Show("------------- Upload failed.");
                                    break;
                                }
                        }
                    };
                    request.ResponseReceived += (Google.Apis.Drive.v3.Data.File f) =>
                    {
                        MessageBox.Show($"------------- File uploaded succesfully: {f.Name}");
                    };
                    var progress = await request.UploadAsync();

                    if (progress.Exception != null)
                        throw progress.Exception;
                }
            }
        }
        catch (Exception e)
        {
            e.ShowException();
        }
    }
}

我打算制作一个控制台项目,但我想念点击并制作了一个WPF项目......没关系,只做了两个按钮,然后在代码隐藏中把这个:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private GoogleLogin gl;

    private void Login_Click(object sender, RoutedEventArgs e)
    {
        gl = new GoogleLogin();
        Task.Run(() => gl.GetUserCredentialAsync());
    }

    private void Update_Click(object sender, RoutedEventArgs e)
    {
        Task.Run(() => gl.UpdateFileAsync(System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "- DriveContaDataSave.xml")));
    }
}

DriveFilesLoader是DaImTo类。我用它(并在这里复制/粘贴)只是为了加快速度:

public class DriveFilesLoader
{
    public class FilesListOptionalParms
    {
        /// 

        /// The source of files to list.
        /// 
        public string Corpora { get; set; }
        /// 

        /// A comma-separated list of sort keys. Valid keys are 'createdTime', 'folder', 'modifiedByMeTime', 'modifiedTime', 'name', 'quotaBytesUsed', 'recency', 'sharedWithMeTime', 'starred', and 'viewedByMeTime'. Each key sorts ascending by default, but may be reversed with the 'desc' modifier. Example usage: ?orderBy=folder,modifiedTime desc,name. Please note that there is a current limitation for users with approximately one million files in which the requested sort order is ignored.
        /// 
        public string OrderBy { get; set; }
        /// 

        /// The maximum number of files to return per page.
        /// 
        public int? PageSize { get; set; }
        /// 

        /// The token for continuing a previous list request on the next page. This should be set to the value of 'nextPageToken' from the previous response.
        /// 
        public string PageToken { get; set; }
        /// 

        /// A query for filtering the file results. See the "Search for Files" guide for supported syntax.
        /// 
        public string Q { get; set; }
        /// 

        /// A comma-separated list of spaces to query within the corpus. Supported values are 'drive', 'appDataFolder' and 'photos'.
        /// 
        public string Spaces { get; set; }
        /// 

        /// Selector specifying a subset of fields to include in the response.
        /// 
        public string Fields { get; set; }
        /// 

        /// Alternative to userIp.
        /// 
        public string QuotaUser { get; set; }
        /// 

        /// IP address of the end user for whom the API call is being made.
        /// 
        public string UserIp { get; set; }
    }

    /// 

    /// Lists or searches files. 
    /// Documentation https://developers.google.com/drive/v3/reference/files/list
    /// Generation Note: This does not always build corectly.  Google needs to standardise things I need to figuer out which ones are wrong.
    /// 
    /// Authenticated drive service.  
    /// Optional paramaters.        /// FileListResponse
    public Google.Apis.Drive.v3.Data.FileList ListFiles(DriveService service, FilesListOptionalParms optional = null)
    {
        try
        {
            // Initial validation.
            if (service == null)
                throw new ArgumentNullException("service");

            // Building the initial request.
            var request = service.Files.List();
            if(optional != null)
                ApplyOptionalParameters(ref request, optional);
            // Applying optional parameters to the request.                
            request = (FilesResource.ListRequest)ApplyOptionalParms(request, optional);
            // Requesting data.
            return request.Execute();
        }
        catch (Exception ex)
        {
            throw new Exception("Request Files.List failed.", ex);
        }
    }

    private void ApplyOptionalParameters(ref FilesResource.ListRequest request, FilesListOptionalParms parms)
    {
        if(!string.IsNullOrEmpty(parms.Corpora))
            request.Corpora = parms.Corpora;
        if(!string.IsNullOrEmpty(parms.OrderBy))
            request.OrderBy = parms.OrderBy;
        if (parms.PageSize.HasValue)
            request.PageSize = parms.PageSize;
        if (!string.IsNullOrEmpty(parms.PageToken))
            request.PageToken = parms.PageToken;
        if (!string.IsNullOrEmpty(parms.Q))
            request.Q = parms.Q;
        if (!string.IsNullOrEmpty(parms.Spaces))
            request.Spaces = parms.Spaces;
        if (!string.IsNullOrEmpty(parms.Fields))
            request.Fields = parms.Fields;
        if (!string.IsNullOrEmpty(parms.QuotaUser))
            request.QuotaUser = parms.QuotaUser;
        if (!string.IsNullOrEmpty(parms.UserIp))
            request.UserIp = parms.UserIp;
    }

    /// 

    /// Using reflection to apply optional parameters to the request.  
    /// 
    /// If the optonal parameters are null then we will just return the request as is.
    /// 
    /// The request. 
    /// The optional parameters. 
    /// 
    public object ApplyOptionalParms(object request, object optional)
    {
        if (optional == null)
            return request;

        System.Reflection.PropertyInfo[] optionalProperties = (optional.GetType()).GetProperties();

        foreach (System.Reflection.PropertyInfo property in optionalProperties)
        {
            // Copy value from optional parms to the request.  They should have the same names and datatypes.
            System.Reflection.PropertyInfo piShared = (request.GetType()).GetProperty(property.Name);
            if (property.GetValue(optional, null) != null) // TODO Test that we do not add values for items that are null
                piShared.SetValue(request, property.GetValue(optional, null), null);
        }

        return request;
    }
}

还有Exception扩展,就好像有人想要复制/粘贴以避免编译错误并试试它:

public static class ExceptionExtensions
{
    public static void ShowException(this Exception e, string additionalMessagePrefix = "")
    {
        var msg = $@"{additionalMessagePrefix}
            Error: 
{e.Message} ;

            Trace: 
{e.StackTrace} ;";

        Exception innerEx = e.InnerException;

        while(innerEx != null)
        {
            msg = msg + $@"

            InnerException: 
{(e.InnerException != null ? innerEx.Message : "")} ; 

            InnerException Trace:
{(e.InnerException != null ? innerEx.StackTrace : "")} ;";

            innerEx = innerEx.InnerException;
        }

        System.Windows.MessageBox.Show(msg);
    }
}
c# google-api google-drive-sdk google-api-dotnet-client
1个回答
0
投票

尝试将文件ID添加到对象。

var file = new Google.Apis.Drive.v3.Data.File();
file.Name = System.IO.Path.GetFileName(fullPath);
file.Id = id;
© www.soinside.com 2019 - 2024. All rights reserved.