I’m trying to build a Windows Forms application that uploads database backup files to Google Drive, but I’ve run into this issue with cross-thread operations:
Error Message:
System.InvalidOperationException: ‘Cross-thread operation not valid: Control ‘textBox1’ accessed from a thread other than the thread it was created on.’
This error occurs when I attempt to update the UI controls during the upload progress. Here is my code:
using System;
using System.Windows.Forms;
using System.Threading;
using Google.Apis.Drive.v3;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Util.Store;
namespace DriveUploader
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void btnBrowse_Click(object sender, EventArgs e)
{
OpenFileDialog fileDialog = new OpenFileDialog
{
InitialDirectory = @"C:\",
Title = "Select Database Backup",
CheckFileExists = true,
DefaultExt = "bak",
Filter = "Backup files (*.bak)|*.bak",
RestoreDirectory = true
};
if (fileDialog.ShowDialog() == DialogResult.OK)
{
textBox1.Text = fileDialog.FileName;
}
}
private static string DetectMimeType(string filePath)
{
string contentType = "application/octet-stream";
string extension = System.IO.Path.GetExtension(filePath).ToLower();
Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(extension);
if (key != null && key.GetValue("Content Type") != null)
contentType = key.GetValue("Content Type").ToString();
return contentType;
}
public void AuthenticateAndUpload()
{
string[] permissions = new string[] { DriveService.Scope.Drive };
var clientId = "{YOUR_CLIENT_ID}";
var clientSecret = "{YOUR_CLIENT_SECRET}";
var credentials = GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId = clientId,
ClientSecret = clientSecret
},
permissions,
Environment.UserName,
CancellationToken.None,
new FileDataStore("DriveTokens")
).Result;
DriveService driveService = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credentials,
ApplicationName = "BackupUploader"
});
driveService.HttpClient.Timeout = TimeSpan.FromMinutes(60);
var result = PerformUpload(driveService, textBox1.Text, "");
MessageBox.Show("Upload finished: " + result);
}
public Google.Apis.Drive.v3.Data.File PerformUpload(DriveService service, string filePath, string parentId)
{
if (System.IO.File.Exists(filePath))
{
var fileMetadata = new Google.Apis.Drive.v3.Data.File()
{
Name = System.IO.Path.GetFileName(filePath),
Description = "Uploaded via C#",
MimeType = DetectMimeType(filePath)
};
byte[] fileBytes = System.IO.File.ReadAllBytes(filePath);
System.IO.MemoryStream fileStream = new System.IO.MemoryStream(fileBytes);
try
{
var uploadRequest = service.Files.Create(fileMetadata, fileStream, DetectMimeType(filePath));
uploadRequest.SupportsTeamDrives = true;
uploadRequest.ProgressChanged += OnProgressUpdate;
uploadRequest.ResponseReceived += OnUploadComplete;
uploadRequest.Upload();
return uploadRequest.ResponseBody;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Upload Failed");
return null;
}
}
else
{
MessageBox.Show("File not found", "Error");
return null;
}
}
private void OnProgressUpdate(Google.Apis.Upload.IUploadProgress progress)
{
textBox1.Text += progress.Status + " " + progress.BytesSent;
}
private void OnUploadComplete(Google.Apis.Drive.v3.Data.File file)
{
if (file != null)
{
MessageBox.Show("Upload successful: " + file.Id);
}
}
private void btnUpload_Click(object sender, EventArgs e)
{
AuthenticateAndUpload();
}
}
}
Can anyone help me resolve this threading issue? The error shows up in the OnProgressUpdate method where I attempt to update the text box.