5
votes

Can someone please provide an example of how to use Google.Apis.Storage.v1 for uploading files to google cloud storage in c#?

8

8 Answers

10
votes

I found that this basic operation is not as straight forward as you might expect. Google's documentation about it's Storage API is lacking in information about using it in C# (or any other .NET language). Searching for 'how to upload file to google cloud storage in c#' didn't exactly help me, so here is my working solution with some comments:

Preparation:

  1. You need to create OAuth2 account in your Google Developers Console - go to Project/APIs & auth/Credentials.

  2. Copy Client ID & Client Secret to your code. You will also need your Project name.

Code (it assumes that you've added Google.Apis.Storage.v1 via NuGet):

First, you need to authorize your requests:

var clientSecrets = new ClientSecrets();
clientSecrets.ClientId = clientId;
clientSecrets.ClientSecret = clientSecret;
//there are different scopes, which you can find here https://cloud.google.com/storage/docs/authentication
var scopes = new[] {@"https://www.googleapis.com/auth/devstorage.full_control"};

var cts = new CancellationTokenSource();
var userCredential = await GoogleWebAuthorizationBroker.AuthorizeAsync(clientSecrets,scopes, "yourGoogle@email", cts.Token);

Sometimes you might also want to refresh authorization token via:

await userCredential.RefreshTokenAsync(cts.Token);

You also need to create Storage Service:

var service = new Google.Apis.Storage.v1.StorageService();

Now you can make requests to Google Storage API. Let's start with creating a new bucket:

var newBucket = new Google.Apis.Storage.v1.Data.Bucket()
{
    Name = "your-bucket-name-1"
};

var newBucketQuery = service.Buckets.Insert(newBucket, projectName);
newBucketQuery.OauthToken = userCredential.Result.Token.AccessToken;
//you probably want to wrap this into try..catch block
newBucketQuery.Execute();

And it's done. Now, you can send a request to get list of all of your buckets:

var bucketsQuery = service.Buckets.List(projectName);
bucketsQuery.OauthToken = userCredential.Result.Token.AccessToken;
var buckets = bucketsQuery.Execute();

Last part is uploading new file:

//enter bucket name to which you want to upload file
var bucketToUpload = buckets.Items.FirstOrDefault().Name;
var newObject = new Object()
{
    Bucket = bucketToUpload,
    Name = "some-file-"+new Random().Next(1,666)
};

FileStream fileStream = null;
try
{
    var dir = Directory.GetCurrentDirectory();
    var path = Path.Combine(dir, "test.png");
    fileStream = new FileStream(path, FileMode.Open);
    var uploadRequest = new Google.Apis.Storage.v1.ObjectsResource.InsertMediaUpload(service, newObject,
    bucketToUpload,fileStream,"image/png");
    uploadRequest.OauthToken = userCredential.Result.Token.AccessToken;
    await uploadRequest.UploadAsync();
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}
finally
{
    if (fileStream != null)
    {
        fileStream.Dispose();
    }
}

And bam! New file will be visible in you Google Developers Console inside of selected bucket.

5
votes

This is for Google.Cloud.Storage.V1 (not Google.Apis.Storage.v1), but appears to be a bit simpler to perform an upload now. I started with the Client libraries "Getting Started" instructions to create a service account and bucket, then experimented to find out how to upload an image.

The process I followed was:

  1. Sign up for Google Cloud free trial
  2. Create a new project in Google Cloud (remember the project name\ID for later)
  3. Create a Project Owner service account - this will result in a json file being downloaded that contains the service account credentials. Remember where you put that file.
  4. The getting started docs get you to add the path to the JSON credentials file into an environment variable called GOOGLE_APPLICATION_CREDENTIALS - I couldn't get this to work through the provided instructions. Turns out it is not required, as you can just read the JSON file into a string and pass it to the client constructor.
  5. I created an empty WPF project as a starting point, and a single ViewModel to house the application logic.
  6. Install the Google.Cloud.Storage.V1 nuget package and it should pull in all the dependencies it needs.

Onto the code.

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; }
}
5
votes

You can use Google Cloud APIs without SDK in the following ways:

  1. Required api-key.json file
  2. Install package Google.Apis.Auth.OAuth2 in order to authorize the HTTP web request
  3. You can set the default configuration for your application in this way
  4. I did the same using .NET core web API and details are given below:

Url details:

"GoogleCloudStorageBaseUrl": "https://www.googleapis.com/upload/storage/v1/b/", "GoogleSpeechBaseUrl": "https://speech.googleapis.com/v1/operations/", "GoogleLongRunningRecognizeBaseUrl": "https://speech.googleapis.com/v1/speech:longrunningrecognize", "GoogleCloudScope": "https://www.googleapis.com/auth/cloud-platform",

public void GetConfiguration()
    {
        // Set global configuration
        bucketName = _configuration.GetValue<string>("BucketName");
        googleCloudStorageBaseUrl = _configuration.GetValue<string>("GoogleCloudStorageBaseUrl");
        googleSpeechBaseUrl = _configuration.GetValue<string>("GoogleSpeechBaseUrl");
        googleLongRunningRecognizeBaseUrl = _configuration.GetValue<string>("GoogleLongRunningRecognizeBaseUrl");

        // Set google cloud credentials
        string googleApplicationCredentialsPath = _configuration.GetValue<string>("GoogleCloudCredentialPath");
        using (Stream stream = new FileStream(googleApplicationCredentialsPath, FileMode.Open, FileAccess.Read))
            googleCredential = GoogleCredential.FromStream(stream).CreateScoped(_configuration.GetValue<string>("GoogleCloudScope"));

    }

Get Oauth token:

public string GetOAuthToken()
    {
        return googleCredential.UnderlyingCredential.GetAccessTokenForRequestAsync("https://accounts.google.com/o/oauth2/v2/auth", CancellationToken.None).Result;
    }

To upload file to cloud bucket:

public async Task<string> UploadMediaToCloud(string filePath, string objectName = null)
    {
        string bearerToken = GetOAuthToken();

        byte[] fileBytes = File.ReadAllBytes(filePath);
        objectName = objectName ?? Path.GetFileName(filePath);

        var baseUrl = new Uri(string.Format(googleCloudStorageBaseUrl + "" + bucketName + "/o?uploadType=media&name=" + objectName + ""));

        using (WebClient client = new WebClient())
        {
            client.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + bearerToken);
            client.Headers.Add(HttpRequestHeader.ContentType, "application/octet-stream");

            byte[] response = await Task.Run(() => client.UploadData(baseUrl, "POST", fileBytes));
            string responseInString = Encoding.UTF8.GetString(response);
            return responseInString;
        }
    }

In order to perform any action to the cloud API, just need to make a HttpClient get/post request as per the requirement.

Thanks

3
votes

Use of Google.Apis.Storage.v1 for uploading files using SDK to google cloud storage in c#:

  1. Required api-key.json file

  2. Install the package Google.Cloud.Storage.V1; and Google.Apis.Auth.OAuth2;

  3. The code is given below to upload the file to the cloud

    private string UploadFile(string localPath, string objectName = null)
        {
            string projectId = ((Google.Apis.Auth.OAuth2.ServiceAccountCredential)googleCredential.UnderlyingCredential).ProjectId;
    
            try
            {
                // Creates the new bucket.
                var objResult = storageClient.CreateBucket(projectId, bucketName);
                if (!string.IsNullOrEmpty(objResult.Id))
                {
                    // Upload file to google cloud server
                    using (var f = File.OpenRead(localPath))
                    {
                        objectName = objectName ?? Path.GetFileName(localPath);
                        var objFileUploadStatus1 = storageClient.UploadObject(bucketName, objectName, null, f);
                    }
                }
            }
            catch (Google.GoogleApiException ex)
            {
                // Error code =409, means bucket already created/exist then upload file in the bucket
                if (ex.Error.Code == 409)
                {
                    // Upload file to google cloud server
                    using (var f = File.OpenRead(localPath))
                    {
                        objectName = objectName ?? Path.GetFileName(localPath);
                        var objFileUploadStatus2 = storageClient.UploadObject(bucketName, objectName, null, f);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
            return objectName;
        }
    
    1. To set the credentials

      private bool SetStorageCredentials()
      {
          bool status = true;
          try
          {
              if (File.Exists(credential_path))
              {
                  Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", credential_path);
                  using (Stream objStream = new FileStream(Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS"), FileMode.Open, FileAccess.Read))
                      googleCredential = GoogleCredential.FromStream(objStream);
                  // Instantiates a client.
                  storageClient = StorageClient.Create();
                  channel = new Grpc.Core.Channel(SpeechClient.DefaultEndpoint.Host, googleCredential.ToChannelCredentials());
              }
              else
              {
                  DialogResult result = MessageBox.Show("File " + Path.GetFileName(credential_path) + " does not exist. Please provide the correct path.");
                  if (result == System.Windows.Forms.DialogResult.OK)
                  {
                      status = false;
                  }
              }
          }
          catch (Exception ex)
          {
              MessageBox.Show(ex.ToString());
              status = false;
          }
          return status;
      }
      

I used SDK in one of my window application. You can use the same code according to your needs/requirements.

1
votes

You'll be happy to know it still works in 2016... I was googling all over using fancy key words like "google gcp C# upload image", until I just plain asked the question: "How do I upload an image to google bucket using C#"... and here I am. I removed the .Result in the user credential, and this was the final edit that worked for me.

            // ******

    static string bucketForImage = ConfigurationManager.AppSettings["testStorageName"];
    static string projectName = ConfigurationManager.AppSettings["GCPProjectName"];

            string gcpPath = Path.Combine(Server.MapPath("~/Images/Gallery/"), uniqueGcpName + ext);
            var clientSecrets = new ClientSecrets();
            clientSecrets.ClientId = ConfigurationManager.AppSettings["GCPClientID"];
            clientSecrets.ClientSecret = ConfigurationManager.AppSettings["GCPClientSc"];

            var scopes = new[] { @"https://www.googleapis.com/auth/devstorage.full_control" };
            var cts = new CancellationTokenSource();
            var userCredential = await GoogleWebAuthorizationBroker.AuthorizeAsync(clientSecrets, scopes, ConfigurationManager.AppSettings["GCPAccountEmail"], cts.Token);
            var service = new Google.Apis.Storage.v1.StorageService();
            var bucketToUpload = bucketForImage;
            var newObject = new Google.Apis.Storage.v1.Data.Object()
            {
                Bucket = bucketToUpload,
                Name = bkFileName
            };

            FileStream fileStream = null;
            try
            {
                fileStream = new FileStream(gcpPath, FileMode.Open);
                var uploadRequest = new Google.Apis.Storage.v1.ObjectsResource.InsertMediaUpload(service, newObject,
                bucketToUpload, fileStream, "image/"+ ext);
                uploadRequest.OauthToken = userCredential.Token.AccessToken;
                await uploadRequest.UploadAsync();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                if (fileStream != null)
                {
                    fileStream.Dispose();
                }
            }

            // ******
0
votes

Here are 2 examples that helped me to upload files to a bucket in Google Cloud Storage with Google.Cloud.Storage.V1 (not Google.Apis.Storage.v1):

Upload files to Google cloud storage using c#

Uploading .csv Files to Google Cloud Storage using C# .Net

I got both working on a C# Console Application just for testing purposes.

0
votes

@February 2021

string _projectId = "YOUR-PROJECT-ID-GCP"; //ProjectID also present in the json file
GoogleCredential _credential = GoogleCredential.FromFile("credential-cloud-file-123418c9e06c.json");

/// <summary>
/// UploadFile to GCS Bucket
/// </summary>
/// <param name="bucketName"></param>
/// <param name="localPath">my-local-path/my-file-name</param>
/// <param name="objectName">my-file-name</param>
public void UploadFile(string bucketName, string localPath, string objectName)
{
    var storage = StorageClient.Create(_credential);
    using var fileStream = File.OpenRead(localPath);
    storage.UploadObject(bucketName, objectName, null, fileStream);
    Console.WriteLine($"Uploaded {objectName}.");
}

You get the credentials JSON file from the google cloud portal where you create a bucket under your project..