7
6

More than 3 years have passed since last update.

asp.net coreでサービス作ったから宣伝兼ねて技術公開する -2_5.ファイルアップロード画面→Amazon S3 アップロード-

Posted at

ファイルアップロードのサンプルコード

やっとここまで来ました。。。これで
さて、今回のサービスですが、写真を撮って、サーバへアップロードする必要がございます。

ファイルアップロードに関しては、Microsoft Docsにサンプルがございましたので、そのまま利用可能でした。

FileUploadSample:
https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/mvc/models/file-uploads/sample/FileUploadSample

しかーし、今見てみたらなんとリンク切れ。

どうやら core 3系のサンプルと統合されたようで、こちらになります。
https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/mvc/models/file-uploads/samples/2.x/SampleApp

またリンク先が変わるかもしれませんので、その際はAspNetCore.DocsをGitで検索ください。

ファイルアップロードの実装

サンプルから一部抜粋し、Workへ実装しましょう!

Views\Work\Index.cshtml
@{
    ViewData["Title"] = "Work Page";
}

<div class="text-center">
    <h1 class="display-4">Working Page</h1>
</div>

<hr>

<form method="post" enctype="multipart/form-data" asp-controller="Work" asp-action="FileUpload">
    <div class="form-group">
        <div class="col-md-4">
            <p>ファイルアップロード</p>
            <input type="file" name="files" multiple />
        </div>
        <div class="col-md-2">
            <input type="submit" value="Upload" />
        </div>
    </div>
</form>

次に、これを受け付けるコントローラ実装!

Controllers\WorkController.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using sample2_1.Models;

namespace sample2_1.Controllers
{
    public class WorkController : Controller
    {
        public IActionResult Index()
        {
            /* ログインされている場合、共通受け渡しデータにユーザ名を入れておく */
            if (User.Identity.IsAuthenticated)
            {
                var user_id = "";
                var user_nm = "";
                // ユーザIDの特定
                foreach (var i in this.User.Identities)
                {
                    foreach (var n in i.Claims)
                    {
                        if (n.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")
                        {
                            user_id = n.Value;
                        }
                        if (user_id != "") break;
                    }
                    if (user_id != "") break;
                }

                // ユーザマスタから情報取得
                using (var db = new AppDbContext())
                {
                    // [出力]
                    foreach (var mUser in db.MUsers.Where(m => m.UserId == user_id))
                    {
                        user_nm = mUser.UserNm;
                        break;
                    }
                }

                ViewData["user_nm"] = user_nm;
            }



            return View();
        }

        [HttpPost("UploadFiles")]
        public async Task<IActionResult> FileUpload(List<IFormFile> files)
        {
            // 保存先を取得
            string filePath = @"C:\work\";

            // ファイル保存
            long size = files.Sum(f => f.Length);
            foreach (var formFile in files)
            {
                if (formFile.Length <= 0) continue;
                // ローカルに保存
                using (var stream = new FileStream(filePath + formFile.FileName, FileMode.Create))
                {
                    await formFile.CopyToAsync(stream);
                }
            }

            // 画面に返す返却値
            ViewData["uploadResult"] = Ok(new { count = files.Count, size, filePath }).Value.ToString();

            // ViewをIndex画面で返却
            return View("Index");
        }
    }
}

サンプルそのままなのですが、結果を画面に返したいので、ViewData["uploadResult"] へアップロード情報を返します。
ViewData["uploadResult"] に値が入っていた場合に、画面に表示するようにします。

Views\Work\Index.cshtml
@{
    ViewData["Title"] = "Work Page";
}

<div class="text-center">
    <h1 class="display-4">Working Page</h1>
</div>

<hr>

<form method="post" enctype="multipart/form-data" asp-controller="Work" asp-action="FileUpload">
    <div class="form-group">
        <div class="col-md-4">
            <p>ファイルアップロード</p>
            <input type="file" name="files" multiple />
        </div>
        <div class="col-md-2">
            <input type="submit" value="Upload" />
        </div>
    </div>
</form>

@if (ViewData["uploadResult"] != null)
{
    <hr>
    <h5>ファイルアップロード結果 : @ViewData["uploadResult"]</h5>
}
<hr>

デバッグ実行

ログイン後、Work ページへ
image.png

写真を選択
image.png

画面にファイル名が中途半端に表示されます。
image.png

Uploadをクリック
正しくアップロード情報が画面に表示されたことを確認
image.png

ローカスパス:C:\Work\ にファイルが存在しているかを確認
image.png

OK!

一応できるような、複数ファイルアップロードもやってみましょう!

ファイル選択
image.png

4ファイル選択結果!
image.png

Upload!
image.png

出来た!
image.png

それでは、このファイル達をAmazon S3 へファイルアップロードします。

AWS S3接続へ必要なもの

この辺りは他のサイトがとてもわかりやすく説明してくれているので、参考にさせていただいたリンクを張っていきます。
とても助かりました。ありがとう!

1 . AWS アカウント作成

大前提ですな。作成後に色々と気をつける点があるので、是非設定しましょう。

AWSアカウントを取得したら速攻でやっておくべき初期設定まとめ:
 https://qiita.com/tmknom/items/303db2d1d928db720888

2 . AWS S3用のキーを取得する

awsのs3を操作する為のaccess keyとsecret keyを取得する(IAM):
 https://joppot.info/2014/06/14/1621

3 . Visual StudioにAWS用のプラグインをインストールします

クラウドストレージ(Amazon S3)に画像をアップロード、参照する:
 https://leadtools.grapecity.com/topics/news-20170628

これで一旦準備はOK!

Amazon S3アップロードの実装

  1. Amazon S3用のインターフェイスオブジェクト作成
     「IAmazonS3 client」の記述を行います。

  2. Amazon S3 クライアントの設定
     AmazonS3Clientを作成する際に、アクセスキー及び、地域を引数に設定する必要があります。
     アクセスキーはそれぞれ取得していただきますが、地域はそれぞれ異なると思います。
     今回の場合、米国東部(オハイオ)となっております。
     準備の際に設定したリージョンを設定してください。
    image.png
     その他の地域は以下AWSのサイトを参照し、適切な引数の設定をしてください。
      https://docs.aws.amazon.com/ja_jp/general/latest/gr/rande.html

  3. S3上の保存先を設定
     S3 にバケットを作成します。
     その配下にworkフォルダを作成します。
     以下のように設定し、アップロードを行います。

 バケット:tanatoru-s3
 パスキー:work/[アップロードファイル名]

image.png

それでは、実装したソースコードはこちらになります。
通常のファイルアップロードも記載されているので、変更点が見たい場合は上記同名のファイルとWinMerge等を使って比較してみてください。

Controllers\WorkController.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Amazon;
using Amazon.S3;
using Amazon.S3.Transfer;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using sample2_1.Models;
using sample2_1.Models.Const;

namespace sample2_1.Controllers
{
    public class WorkController : Controller
    {
        // 1. Amazon S3用のインターフェイスオブジェクト作成
        private static IAmazonS3 client;

        public IActionResult Index()
        {
            /* ログインされている場合、共通受け渡しデータにユーザ名を入れておく */
            if (User.Identity.IsAuthenticated)
            {
                var user_id = "";
                var user_nm = "";
                // ユーザIDの特定
                foreach (var i in this.User.Identities)
                {
                    foreach (var n in i.Claims)
                    {
                        if (n.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")
                        {
                            user_id = n.Value;
                        }
                        if (user_id != "") break;
                    }
                    if (user_id != "") break;
                }

                // ユーザマスタから情報取得
                using (var db = new AppDbContext())
                {
                    // [出力]
                    foreach (var mUser in db.MUsers.Where(m => m.UserId == user_id))
                    {
                        user_nm = mUser.UserNm;
                        break;
                    }
                }

                ViewData["user_nm"] = user_nm;
            }



            return View();
        }

        [HttpPost("UploadFiles")]
        public async Task<IActionResult> FileUpload(List<IFormFile> files)
        {
            // 保存先を取得
            string filePath = @"C:\work\";

            // 2. Amazon S3 クライアントの設定
            // Amazon S3 キーを取得(準備で取得したキーを設定してください。)
            // このキーがバレると、勝手に使われてしまう可能性があるので、お気をつけて
            var accessKey = ConstKey.AWS_KEY;
            var accessSecretKey = ConstKey.AWS_SECRET_KEY;

            // ファイル保存
            long size = files.Sum(f => f.Length);
            foreach (var formFile in files)
            {
                if (formFile.Length <= 0) continue;
                // ローカルに保存
                using (var stream = new FileStream(filePath + formFile.FileName, FileMode.Create))
                {
                    await formFile.CopyToAsync(stream);
                }

                // Amazon S3 クライアントの設定
                client = new AmazonS3Client(accessKey
                                           , accessSecretKey
                                           , RegionEndpoint.USEast2);
                // 非同期メソッドの実行
                WritingAnObjectAsync(formFile.FileName).Wait();


            }

            // 画面に返す返却値
            ViewData["uploadResult"] = Ok(new { count = files.Count, size, filePath }).Value.ToString();

            // ViewをIndex画面で返却
            return View("Index");
        }

        // S3 ストレージへアップロード!
        static async Task WritingAnObjectAsync(string s_upd_file_nm)
        {

            // 3. S3上の保存先を設定
            string S3BucketName = @"tanatoru-s3";
            string S3Key = @"work/";

            // 元のファイル名をそのまま利用
            S3Key += s_upd_file_nm;

            try
            {
                // キーを設定したclientを引数に、アップロードクラスを取得
                var fileTransferUtility = new TransferUtility(client);

                // アップロード処理
                using (var fileToUpload =
                    new FileStream(@"c:\work\" + s_upd_file_nm, FileMode.Open, FileAccess.Read))
                {
                    await fileTransferUtility.UploadAsync(fileToUpload
                                                        ,S3BucketName
                                                        ,S3Key);
                }
                // OK!
                Console.WriteLine("Upload 3 completed");

            }
            catch (AmazonS3Exception e)
            {
                Console.WriteLine(
                        "Error encountered ***. Message:'{0}' when writing an object"
                        , e.Message);
            }
            catch (Exception e)
            {
                Console.WriteLine(
                    "Unknown encountered on server. Message:'{0}' when writing an object"
                    , e.Message);
            }
        }
    }
}

ところどころソースはサンプルからそのままですが、まぁ使えると思えます。
また、usingにAWS系はかなり増えているので、お忘れなく。

デバッグ実行(Amazon S3 ver)

まずは、前回同様アップロード
image.png

結果はOK
image.png

それではそれぞれのファイルを確認しましょう。
まずはローカル、当然OK。
image.png

次にAmazon S3、こちらもOK!
image.png

これでAmazon S3 ストレージへのアップロードが行えました。
本来はダウンロードも書きたいのですが、実はまだTanaToruに未実装なもので、後回しですね。。。
他にサンプルは山ほどあるとは思いますが、コメント頂ければいつか書きます。

おまけ

あまり必要ないとは思いますが、AWSキーを取得するConstファイルを隠すとこ隠して記載しておきます。

Models\Const\ConstKey.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace sample2_1.Models.Const
{
    public class ConstKey
    {
        public const String AWS_KEY = @"Your AWS_KEY !";
        public const String AWS_SECRET_KEY = @"Your AWS_SECRET_KEY !";
    }
}

このファイルを作っておけばサンプルは作れると思います。

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6