GCS(Google Cloud Storage)への保存は、公式ドキュメントを見れば良いのですが、躓きました。
とりあえずローカル保存を試してみたが、エラー
System.InvalidOperationException HResult=0x80131509 Message=The Application Default Credentials are not available. They are available if running in Google Compute Engine. Otherwise, the environment variable GOOGLE_APPLICATION_CREDENTIALS must be defined pointing to a file defining the credentials. See https://developers.google.com/accounts/docs/application-default-credentials for more information. Source=Google.Apis.Auth スタック トレース: at Google.Apis.Auth.OAuth2.DefaultCredentialProvider.<CreateDefaultCredentialAsync>d__11.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Google.Api.Gax.Rest.ScopedCredentialProvider.<CreateDefaultCredentialsUncached>d__5.MoveNext() at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Google.Api.Gax.TaskExtensions.WaitWithUnwrappedExceptions(Task task) at Google.Cloud.Storage.V1.StorageClient.Create(GoogleCredential credential, EncryptionKey encryptionKey) at GoogleCloudSamples.StorageQuickstart.Main(String[] args) in
Google Compute Engineで動かすにはGOOGLE_APPLICATION_CREDENTIALの環境変数の設定が必要です。
ASP.NET Core + Google App Engineで
ですが、Google App Engineの場合は、環境変数の設定が必要ありません。
今回はASP.NET CoreにWebサービスにアップロードされたファイルをGoogle Cloud Storageに保存するプログラムを書いてみました。
@{ ViewData["Title"] = "Home Page"; } @using (Html.BeginForm( "Index", // アクション名 "Share", // コントローラー名 FormMethod.Post, // HTTP メソッド new { enctype = "multipart/form-data" } // その他の属性 )) { <div class="form-group"> <div class="col-md-10"> <p>Upload one or more files using this form:</p> <input type="file" name="files"> </div> </div> <div class="form-group"> <div class="col-md-10"> <input type="submit" value="Upload"> </div> </div> }
- IFormFileをインターフェースとして受け取る
- 受け取ったファイルを一時ファイルとして保存
- 一時ファイルをGCSのバゲットに保存
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Google.Cloud.Storage.V1; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace OTRSPlusCloud.Controllers { public class ShareController : Controller { private const string BucketName = "自分で宣言してね"; [HttpPost] public async Task<IActionResult> Index(List<IFormFile> files) { long size = files.Sum(f => f.Length); // full path to file in temp location var filePath = Path.GetTempFileName(); foreach (var formFile in files) { if (formFile.Length > 0) { using (var stream = new FileStream(filePath, FileMode.Create)) { await formFile.CopyToAsync(stream); } UploadFile(BucketName, filePath, formFile.FileName); } } // process uploaded files // Don't rely on or trust the FileName property without validation. return Ok(new { count = files.Count, size, filePath }); } private void UploadFile(string bucketName, string localPath, string objectName = null) { var storage = StorageClient.Create(); using (var f = System.IO.File.OpenRead(localPath)) { objectName = objectName ?? Path.GetFileName(localPath); storage.UploadObject(bucketName, objectName, null, f); Console.WriteLine($"Uploaded {objectName}."); } } } }
サイズの大きなデータには
さすがにこの方法ではサイズが大きいデータは扱えません。
その場合はGCSへの署名付きURLを発行することになります。
方法は後日書きます。