如何从 c# windows 应用程序上传 google 驱动器中的备份数据库文件?

How to upload backup database file in google drive from c# windows application?

错误

System.InvalidOperationException: 'Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on.'

 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 Google.Apis;
 using Google.Apis.Auth;
 using Google.Apis.Drive.v3;
 using Google.Apis.Auth.OAuth2;
 using Google.Apis.Util.Store;
 using Google.Apis.Services;
 using System.Windows.Forms; 
 namespace GDrive_Sample 
 {
    public partial class Form1 : Form{public Form1(
    {
       InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        OpenFileDialog openFileDialog1 = new OpenFileDialog
        {
            InitialDirectory = @"D:\",
            Title = "Browse Backup Files",

            CheckFileExists = true,
            CheckPathExists = true,

            DefaultExt = "bak",
            Filter = "bak files (*.bak)|*.bak",
            FilterIndex = 2,
            RestoreDirectory = true,

            ReadOnlyChecked = true,
            ShowReadOnly = true
        };

        if (openFileDialog1.ShowDialog() == DialogResult.OK)
        {
            textBox1.Text = openFileDialog1.FileName;
        }
    }

    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 && regKey.GetValue("Content Type") != null)
            mimeType = regKey.GetValue("Content Type").ToString();
        return mimeType;
    }

    public void Authorize()
    {
        string[] scopes = new string[] { DriveService.Scope.Drive,
                           DriveService.Scope.DriveFile,};
        // var clientId = "{REDACTED}";      // From https://console.developers.google.com  
        //var clientSecret = "{REDACTED}";          // 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 clientId = "{REDACTED}";
        var clientSecret = "{REDACTED}";
        //var clientId = "{REDACTED}";
        //var clientSecret = "{REDACTED}";

        var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets
        {
            ClientId = clientId,
            ClientSecret = clientSecret
        }, scopes,
        Environment.UserName, CancellationToken.None, new FileDataStore("MyAppsToken")).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.   

        DriveService service = new DriveService(new BaseClientService.Initializer()
        {
            HttpClientInitializer = credential,
            ApplicationName = "uploadclient",

        });
        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  
        // team drive root https://drive.google.com/drive/folders/0AAE83zjNwK-GUk9PVA   
        //string uploadfile = @"C:\Users\hp\Downloads\settings.png";
        var responce = uploadFile(service, textBox1.Text, "");
        //var respocne = uploadFile(service, uploadfile, "");
        // 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--" + responce);
    }

    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<string> { _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.Upload();
                return request.ResponseBody;
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message, "Error Occured");
                return null;
            }
        }
        else
        {
            MessageBox.Show("The file does not exist.", "404");
            return null;
        }
    }

    private void Request_ProgressChanged(Google.Apis.Upload.IUploadProgress obj)
    {
        textBox1.Text += obj.Status + " " + obj.BytesSent;
    }

    private void Request_ResponseReceived(Google.Apis.Drive.v3.Data.File obj)
    {
        if (obj != null)
        {
            MessageBox.Show("File was uploaded sucessfully--" + obj.Id);
        }
    }

    public void button2_Click(object sender, EventArgs e)
    {
        Authorize();
        
    }
  }
}

您的问题本质上归结为一个非常简单的问题。您只能从 UI 线程更新控件。不是来自后台线程。

你的问题是这段代码:

private void Request_ProgressChanged(Google.Apis.Upload.IUploadProgress obj)
{
    textBox1.Text += obj.Status + " " + obj.BytesSent;
}

Request_ProgressChanged 正在从后台线程异步调用。然而您正在尝试更新 textBox1 文本。

您可以将其更改为:

private void Request_ProgressChanged(Google.Apis.Upload.IUploadProgress obj)
{
    textBox1.BeginInvoke((Action)(() => textBox1.Text += obj.Status + " " + obj.BytesSent));
}

BeginInvoke 告诉您的应用程序将调用编组回 UI 线程并让它完成工作。您将需要在任何尝试从后台线程更新 UI 的地方执行此操作。

这可能会变得乏味,因此您还可以使用诸如 PostSharp 之类的库,这些库允许您在 UI 线程上向想要 运行 的方法添加属性,而不是不断地编写样板文件 https://dotnetcoretutorials.com/2020/12/10/simplifying-multithreaded-scenarios-with-postsharp-threading/