使用Progress Bar WPF进行异步Google文件上传

时间:2018-03-25 02:40:18

标签: c# .net wpf progress-bar google-cloud-storage

我使用服务帐户上传到Google云端存储。我需要能够在WPF UI中显示上传的进度。现在,每当我尝试更新ProgressBar.Value时,它都不起作用,但是当我在控制台中编写bytesSent时,我可以看到进度。

    public async Task<bool> UploadToGoogleCloudStorage(string bucketName, string token, string filePath, string contentType)
    {
        var newObject = new Google.Apis.Storage.v1.Data.Object()
        {
            Bucket = bucketName,
            Name = System.IO.Path.GetFileNameWithoutExtension(filePath)
        };
        var service = new Google.Apis.Storage.v1.StorageService();

        try
        {
            using (var fileStream = new FileStream(filePath, FileMode.Open))
            {

                var uploadRequest = new ObjectsResource.InsertMediaUpload(service, newObject, bucketName, fileStream, contentType);
                uploadRequest.OauthToken = token;
                ProgressBar.Maximum = fileStream.Length;
                uploadRequest.ProgressChanged += UploadProgress;
                uploadRequest.ChunkSize = (256 * 1024);
                await uploadRequest.UploadAsync().ConfigureAwait(false);
                service.Dispose();

            }

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            throw ex;
        }
        return true;
    }

    private void UploadProgress(IUploadProgress progress)
    {
        switch (progress.Status)
        {
            case UploadStatus.Starting:
                ProgressBar.Minimum = 0;
                ProgressBar.Value = 0;

                break;
            case UploadStatus.Completed:
                System.Windows.MessageBox.Show("Upload completed!");
                break;
            case UploadStatus.Uploading:
                //Console.WriteLine(progress.BytesSent); -> This is working if I don't call the method below.
                UpdateProgressBar(progress.BytesSent);
                break;
            case UploadStatus.Failed:
                Console.WriteLine("Upload failed "
                            + Environment.NewLine
                            + progress.Exception.Message
                            + Environment.NewLine
                            + progress.Exception.StackTrace
                            + Environment.NewLine
                            + progress.Exception.Source
                            + Environment.NewLine
                            + progress.Exception.InnerException
                            + Environment.NewLine
                            + "HR-Result" + progress.Exception.HResult);
                break;
        }
    }

    private void UpdateProgressBar(long value)
    {
        Dispatcher.Invoke(() => { this.ProgressBar.Value = value; });
    }

1 个答案:

答案 0 :(得分:0)

我尽可能多地重新创建了您的项目,并在图片上传时正确更新了进度条。鉴于您的回调在写入控制台时仍然有效,因此您可能只是在UI本身使用ProgressBar的方式存在问题。

请继续阅读,了解我为使其发挥作用所做的工作。

End result - uploading with progress updates

这适用于Google.Cloud.Storage.V1(不是Google.Apis.Storage.v1),但现在执行上传似乎更简单一些。我从Client libraries "Getting Started" instructions开始创建服务帐户和存储桶,然后进行实验以了解如何上传图像。

我遵循的流程:

  1. Sign up用于Google Cloud免费试用
  2. 在Google Cloud中创建一个新项目(请记住项目名称\ ID以供日后使用)
  3. Create a Project Owner service account - 这将导致下载包含服务帐户凭据的json文件。记住放置该文件的位置。
  4. 入门文档让您将JSON凭证文件的路径添加到名为GOOGLE_APPLICATION_CREDENTIALS的环境变量中 - 我无法通过提供的说明进行操作。事实证明它不是必需的,因为您可以将JSON文件读入字符串并将其传递给客户端构造函数。
  5. 我创建了一个空的WPF项目作为起点,并创建了一个ViewModel来容纳应用程序逻辑。
  6. 安装Google.Cloud.Storage.V1 nuget包,它应该引入所需的所有依赖项。
  7. 代码。

    MainWindow.xaml

    <StackPanel>
        <Button
            Margin="50"
            Height="50"
            Content="BEGIN UPLOAD"
            Click="OnButtonClick" />
        <ContentControl
            Content="{Binding Path=ProgressBar}" />
    </StackPanel>
    

    MainWindow.xaml.cs

    public partial class MainWindow
    {
        readonly ViewModel _viewModel;
    
        public MainWindow()
        {
            _viewModel = new ViewModel(Dispatcher);
            DataContext = _viewModel;
            InitializeComponent();
        }
    
        void OnButtonClick(object sender, RoutedEventArgs args)
        {
            _viewModel.UploadAsync().ConfigureAwait(false);
        }
    }
    

    ViewModel.cs

    public class ViewModel
    {
        readonly Dispatcher _dispatcher;
    
        public ViewModel(Dispatcher dispatcher)
        {
            _dispatcher = dispatcher;
            ProgressBar = new ProgressBar {Height=30};
        }
    
        public async Task UploadAsync()
        {
            // Google Cloud Platform project ID.
            const string projectId = "project-id-goes-here";
    
            // The name for the new bucket.
            const string bucketName = projectId + "-test-bucket";
    
            // Path to the file to upload
            const string filePath = @"C:\path\to\image.jpg";
    
            var newObject = new Google.Apis.Storage.v1.Data.Object
            {
                Bucket = bucketName,
                Name = System.IO.Path.GetFileNameWithoutExtension(filePath),
                ContentType = "image/jpeg"
            };
    
            // read the JSON credential file saved when you created the service account
            var credential = Google.Apis.Auth.OAuth2.GoogleCredential.FromJson(System.IO.File.ReadAllText(
                @"c:\path\to\service-account-credentials.json"));
    
            // Instantiates a client.
            using (var storageClient = Google.Cloud.Storage.V1.StorageClient.Create(credential))
            {
                try
                {
                    // Creates the new bucket. Only required the first time.
                    // You can also create buckets through the GCP cloud console web interface
                    storageClient.CreateBucket(projectId, bucketName);
                    System.Windows.MessageBox.Show($"Bucket {bucketName} created.");
    
                    // Open the image file filestream
                    using (var fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.Open))
                    {
                        ProgressBar.Maximum = fileStream.Length;
    
                        // set minimum chunksize just to see progress updating
                        var uploadObjectOptions = new Google.Cloud.Storage.V1.UploadObjectOptions
                        {
                            ChunkSize = Google.Cloud.Storage.V1.UploadObjectOptions.MinimumChunkSize
                        };
    
                        // Hook up the progress callback
                        var progressReporter = new Progress<Google.Apis.Upload.IUploadProgress>(OnUploadProgress);
    
                        await storageClient.UploadObjectAsync(
                                newObject, 
                                fileStream,
                                uploadObjectOptions,
                                progress: progressReporter)
                            .ConfigureAwait(false);
                    }
    
                }
                catch (Google.GoogleApiException e)
                    when (e.Error.Code == 409)
                {
                    // When creating the bucket - The bucket already exists.  That's fine.
                    System.Windows.MessageBox.Show(e.Error.Message);
                }
                catch (Exception e)
                {
                    // other exception
                    System.Windows.MessageBox.Show(e.Message);
                }
            }
        }
    
        // Called when progress updates
        void OnUploadProgress(Google.Apis.Upload.IUploadProgress progress)
        {
            switch (progress.Status)
            {
                case Google.Apis.Upload.UploadStatus.Starting:
                    ProgressBar.Minimum = 0;
                    ProgressBar.Value = 0;
    
                    break;
                case Google.Apis.Upload.UploadStatus.Completed:
                    ProgressBar.Value = ProgressBar.Maximum;
                    System.Windows.MessageBox.Show("Upload completed");
    
                    break;
                case Google.Apis.Upload.UploadStatus.Uploading:
                    UpdateProgressBar(progress.BytesSent);
    
                    break;
                case Google.Apis.Upload.UploadStatus.Failed:
                    System.Windows.MessageBox.Show("Upload failed"
                                                   + Environment.NewLine
                                                   + progress.Exception);
                    break;
            }
        }
    
        void UpdateProgressBar(long value)
        {
            _dispatcher.Invoke(() => { ProgressBar.Value = value; });
        }
    
        // probably better to expose progress value directly and bind to 
        // a ProgressBar in the XAML
        public ProgressBar ProgressBar { get; }
    }