このサイトは、只今WEB業界で活躍中のデザイナー、プログラマーの方々の情報を集めたweb統合情報サイトです。

Archives Details

Blazor WebAssemblyでAWS SDKを使用しようとしてハマった話

C#

2021.12.27

この記事は最終更新日から1年以上が経過しています。

どもです。

WebAssemblyにWebの未来を感じておりまして、社内カンファレンスでも大いにお話させていただいたのですが、今回Blazor WebAssemblyでAWS SDKを使用しようとしてハマっちゃったよぉと言ったお話です。

検証のプロジェクトで、ファイルをS3にアップロードしたかったので、AWS JavaScript SDKを使う様な感覚で、検証のプロジェクトだからAWS SDK の S3 をフロント側で利用してファイルをアップロードしようと試みてみました。

AWSのキーなどをフロント側で持つ事になりますが、検証のプロジェクトで公開予定もないのでその辺は良いと言うことでサクッと作成しようと思っていたのですが。。。

 

まずは、AWS SDKでサクッとファイルアップロード

node.jsで実装する際は、以下の様なソースコードでS3へのアップロードは可能だと思います。

const AWS = require('aws-sdk');
const fs  = require('fs');

// accessKeyId、secretAccessKeyが記載されたファイル読み込み
AWS.config.loadFromPath('./awskey.json');
AWS.config.update({region: 'AWS region'});

const s3 = new AWS.S3();

// 上記のAWS.configでkey読み込まずにベタ書きの場合
// import { S3Client } from '@aws-sdk/client-s3';
// const s3 = new S3Client({
//   region: 'ap-northeast-1 などAWS region',
//   credentials: {
//     accessKeyId: 'accessKeyId',
//     secretAccessKey: 'secretAccessKey',
//   }
// });

const params = {
 Bucket: "Bucket名",
 Key: "s3 Bucketkey(ファイル・ディレクトリ・パス)"
};

const file = fs.readFileSync("ファイルパス");
params.Body = file;
s3.putObject(params, function(err, data) {
  if (err) console.log(err, err.stack);
  else     console.log(data);
});

こんな感じにサクッといきたかったので調べていたのですが、どうもBlazorのユーザーが少ないのか、日本語記事での情報が少ない。。

多くは海外の情報となってしまう。

色々と参考にしながら、とりあえずはAWS SDKが必要なので、NuGetに取得することに。

Visual StudioのNuGetで右クリックで、「Manage NuGet Packages…」を選択。

「AWSSDK.Core」と「AWSSDK.S3」をインストール。

ひょっとしたら、「AWSSDK.S3」ないかも。。(多分いる)

 

「_imports.razor」に以下を記述。

 

_imports.razor

@using Amazon
@using Amazon.S3
@using Amazon.S3.Model

.NetCore5より「InputFile」コンポーネントが用意されており、inputフォームを使用する際は、こちらを使うと良いみたいなので、使用していく。

<InputFile OnChange="@LoadFiles" multiple />
<button type="submit" @onclick="SubmitFileAsync">Upload</button>

C#のコードは、最小限にするとして以下の様な感じで作成。

@code {
    private AmazonS3Client s3Client;
    private const string BUCKET_NAME = "S3のバケット名";
    private const string FOLDER_NAME = "ディレクトリ名";
    private const double DURATION = 24;

    private Stream _fileStream = null;
    private string _selectedFileName = null;
    private string _objectKey = null;
    private string _contentType = null;

    protected override async Task OnInitializedAsync()
    {
        var config = new AmazonS3Config
        {
            RegionEndpoint = RegionEndpoint.APNortheast1,
            UseAlternateUserAgentHeader = true
        };

        s3Client = new AmazonS3Client("AWS accessKeyId", "AWS secretAccessKey", config);
        await JSRuntime.InvokeAsync<string>("console.log", s3Client);
    }

    public void LoadFiles(InputFileChangeEventArgs e)
    {
        try
        {
            foreach (var file in e.GetMultipleFiles(3))
            {
                StateHasChanged();
                using (Stream stream = file.OpenReadStream())
                {
                    _fileStream = stream;
                    _selectedFileName = file.Name;
                    _objectKey = $"{FOLDER_NAME}/{file.Name}";
                    _contentType = file.ContentType;
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
    }

    public async Task SubmitFileAsync()
    {
        var putObjectRequest = new PutObjectRequest
        {
            BucketName = BUCKET_NAME,
            Key = _objectKey,
            InputStream = _fileStream,
            ContentType = _contentType,
        };
        var response = await s3Client.PutObjectAsync(putObjectRequest);
    }
}

それでは、実行してみると。

ファ。エラー

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: System.Security.Cryptography.Algorithms is not supported on this platform.
System.PlatformNotSupportedException: System.Security.Cryptography.Algorithms is not supported on this platform.
   at System.Security.Cryptography.HMACSHA256..ctor()
   at

エラーを見てみると、

System.Security.Cryptography.Algorithms is not supported on this platform.

だと。。。

どうやら、AWS SDK PutObjectRequest class使用時にエラーがスローされている様子。

AWS SDK PutObjectRequest class

WebAssembly上でのエラーなので調べていると、公式ドキュメントの方には以下の様に記述されている。

System.Security.Cryptography API は、ブラウザーで実行されると、
実行時に PlatformNotSupportedException をスローします。

あぁ。それだ。対応策はと。。

推奨アクション
現時点では、推奨される回避策はありません。

ガーン。。。

BlazorでのAWS SDK使用は対応しているって書いていたはずなのに。。。

よくよく見ていると。。redditにて以下の様なコメントを見つけた。。

みなさん、こんにちは。最新リリース(v3.5.2)では、Blazor WebAssembly ランタイムをサポートするようになりました! SDK チームに感謝します 注:私はAmazon Web Servicesの社員です(たまたまC#が好きなんです!)。 EDIT: リリース後のテストで、Blazor WASMランタイムの.NET 5バージョンに破損があることがわかりました。 System.Security.Cryptography.Algorithms名前空間へのサポートが削除され、ほぼすべてのサービスクライアントが使用しているSigv4署名が失敗することになります。 net core app3.1ランタイムは動きますが。

 

ガーン。。

でも、「net core app3.1ランタイムは動きますが。」と。

という事で、.NET core 3.1で実行していくことに決めたのでやってみることに。

.NET core 3.1では、.NET core 5で使用できるようになったInputFileコンポーネントは使用できない(組み込まれていない)ので、オープンソースの「https://github.com/SteveSandersonMS/BlazorInputFile」をNuGetパッケージで取得して使ってみることに。

インストールしたら、「_imports.razor」にBlazorInputFileを追加。

@using BlazorInputFile;

コンポーネントは、.NET core 5で使用できるようになったInputFileコンポーネントとほぼ同様。

<InputFile OnChange="HandleSelection" />

サンプルソースを参考に、MemoryStream参照のため「System.IO」をusing指定。

@using System.IO;

statusを表示するためのHTMLを記述。

<p>@status</p>

C#のcode箇所。サンプルソース参考。

@code {
    string status;

    async Task HandleSelection(IFileListEntry[] files)
    {
        var file = files.FirstOrDefault();
        if (file != null)
        {
            // Just load into .NET memory to show it can be done
            // Alternatively it could be saved to disk, or parsed in memory, or similar
            var ms = new MemoryStream();
            await file.Data.CopyToAsync(ms);

            status = $"Finished loading {file.Size} bytes from {file.Name}";
        }
    }
}

という事で実行してみると。

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: Could not find 'BlazorInputFile' in 'window'.
      Error: Could not find 'BlazorInputFile' in 'window'.

ブヘー。。windowオブジェクトにBlazorInputFileとかないよエラー。。

https://github.com/SteveSandersonMS/BlazorInputFile」をフォークした「 Agno.BlazorInputFile」というプロジェクトがあり、もしかしたら色々対応しているかもと試してみることに。

using指定は以下のように「Agno.BlazorInputFile」となります。

@using Agno.BlazorInputFile;

コンポーネントは以下の様になります。

<AgnoInputFile OnFileChange="HandleSelection" />

使用してみると。

Unhandled exception rendering component: Could not find 'BlazorInputFile' in 'window'.
      Error: Could not find 'BlazorInputFile' in 'window'.

ぶへー同じエラー。。

もう、わかんねーよー。

というか、レポジトリ見てみるとわかりますが、.NET core 5で使用できるようになっているのでもう使わないでねぇ〜。と記述されているので、そもそも使用しないほうが良いな。。

という事で、色々やった結果、WebAssemblyのガッツリしたセキュリティもあってか、Blazor WebAssemblyのフロントのみのAWS SDK S3アップロードは厳しい感じがありますので、公式ドキュメントに沿って、通常の**.NET core 5 + サーバーサイド(lamdba などサーバーレス)**と言った形にすることにしました。

海外の記事ではありますが、Blazor WebAssemblyでのAWS SDK使用例があったりして参考にしましたが、どうやら**.NET core 5**以前のバージョンの様であって、上手く行かなかったです。。

という事で、次回は、公式ドキュメントに沿ってのアップロードを試して行きたいと思います。

ではではぁ。

またまたぁ。

Comment

Related Article

Blazor WebAssemblyでAWS SDKを使用しようとしてハマった話

2021.12.27

【M1 Mac】dotnet ef ツールで、MySQLを scaffoldする。

2021.10.17

CATEGORY LIST

LATEST NEWS

アーキテクチャConference 2024に参加してきました。

イベント

2024.11.28

Mac minicomでシリアル通信を行う

電子工作

2024.11.21

Mac 容量足りない問題は、外付けSSDで快適に解決!おすすめ外付けSSD

mac

2024.10.16

Z80エミュレータ- EMUZ80の組み立て

電子工作

2024.10.13

Mac VSCodeで、SFML C++開発環境を作る。

C++

2024.09.09

Rust-SDL2 examplesをすべて試す

Rust

2024.09.01

JavaScriptで、DOMを放り投げる処理

JavaScript

2024.07.27

Rustで創る MOS 6502 CPU その2

Rust

2024.07.23

Rustで創る MOS 6502 CPU その1

Rust

2024.07.19

汎用 3D mesh/model viewerを求め。と、簡単に、FBXファイルをglTF(glb)に変換ツールを求め。

C++

2024.06.06

M1 Macで、OpenGL GLUTを使ってコンパイルする

C

2024.04.27

Rust - Actix Web mongo ユーザー登録 JWT認証

Rust

2024.03.24

RANKING

Follow

SPONSOR

現在、掲載募集中です。



Links

About Us

WEBデザイナーの、WEBデザイナーによる、WEBデザイナーの為のサイト。「みんなで書こう!」と仲間を募ってみたが、結局書くのは自分だけとなってしまいました。日々のメモを綴っていきます。

Entry Profile

Graphical FrontEnd Engineer
- Daisuke Takayama

MAD CITY 北九州市で生まれ育つ。20代はバンド活動に明け暮れ、ふと「webデザイナーになりたい。」と思い、デジタルハリウッド福岡校入学。卒業後、数々の賞を受賞、web業界をざわつかせる。
現在、主に、ゲーム制作中心に港区六本木界隈で活動中。

FOLLOW US