備忘録です.
現在研究の一環で音声を使ったWebアプリケーションの開発を行っています. プロトタイプとしてASP.NET Coreを使って音声信号処理をC# 側で,その他のインタフェースをHTML5側で行うような構成をとっています.
今後もASP.NET Coreで運用し続けるのであれば,アクションなどをButtonにバインドしたり,またModelを定義していい感じにシリアライズとか出来るようにするのですが, WebAssemblyの導入も検討しているため,どっちにもすぐに変えやすい,すなわちRazor記法などを一切使わず,APIのみをASP.NET Core側が提供するといった形が望ましいです.
この用件を満たために行ったことを以降で説明します.
PageModelのMethod(Action)を呼び出せるようにする
ASP.NET Core MVCなどは完全な初心者だったため,命名規則など全くわかりませんでした. ドキュメントを眺めてみると,どうもPOSTだったらOnPost~とかそういう名前にすれば良いようです(ページURL忘れた).
ということでこんな感じになります.
public ActionResult OnPostGetUserMcep() // PostなのにGetとは... { return null; // Fix Me }
PageModelにこの様に実装すれば,例えばこのページが/Hoge
でアクセスできるのであれば,
/Hoge?handler=GetUserMcep
に対してPOSTメソッドでアクセスすればこのActionが実行されることになります.
それでは実際に試してみましょう.
...
えぇ...Bad Request...
さて困りました.問題があるようには見えないのですが,どうもだめっぽいです. それでASP.NET Core Ajax Razor Pagesとかで検索してみると,こんな記事が見つかります.
このページを読むとCSRF関係の対策のやつ関係っぽいことがわかります.
このページを参考にTokenを発行してあげて,リクエストに突っ込んであげると無事にPOSTが通りました.
以下サンプルのfetchリクエスト
return fetch('/Hoge?handler=GetUserMcep', { method:"POST", body: obj, headers: { "XSRF-TOKEN": document.querySelector('input[name="__RequestVerificationToken"][type="hidden"]').value }, credentials: 'include' });
Request Bodyからバイナリデータを受けとる
デバッガで眺めてたら取れそうだったのでこんな感じで受け取ります.
byte[] tmp; using (var st = new MemoryStream()) { await Request.Body.CopyToAsync(st); st.Position = 0; tmp = st.ToArray(); }
これだけ. FetchでFileObjectを投げたり,バイナリデータを投げた場合はこんな感じで取るといいと思います.
multipart/form-data なRequestからバイナリデータを受け取る
Fetchでwavファイルを投げた時,そのまま受け取りたくなったので以下のようにして受け取りました.
byte[] wavFile; var wavform = Request.Form.Files?.FirstOrDefault(v => v.Name == "wavform"); if (wavform != null) { using (var st = new MemoryStream()) { await wavform.CopyToAsync(st); st.Seek(0, SeekOrigin.Begin); wavFile = new byte[st.Length]; await st.ReadAsync(wavFile, 0, wavFile.Length); } }
Request.From.Files
からは,FileObjectとして投げられたものを受け取れるので非常に簡単でいいですね.
File以外にもTypedArrayとかを投げることもあるので,そのやり方を確認してみましょう.
var targetArr = Request.Form.FirstOrDefault(v => v.Name == "arr").Value[0].Split(',').Select<string, float>(float.Parse).ToArray();
...たぶんJSONとかでいい感じにやったほうがいい気がするんですけどよくわからないです.
とりあえず自分の目的としていることはこんな感じで実現ができそうでした.
バイナリデータをHTML5(クライアント)側に返す
C# で加工した音声ファイル(float型)のものをクライアント側に返して再生をしたり描画をするためにどうやって返すかを確認してみました.
これは非常に簡単でFileとしてbyteArrayを投げつければいいようです.
var byteArr = new byte[myData.Length * 4]; Buffer.BlockCopy(myData, 0, byteArr, 0, myData.Length * 4); // float32で返すので,4byte return File(byteMcep, "application/octet-stream");
まとめ
- Action名はOn{Method名}{Action名}
- FileObjectやTypedArrayなどを単体で送った際は
Request.Body
をbyteArrayにコピーして使う - multipart/form-dataなものにTypedArrayを送った際は
Request.Form
から,FileObjectであればRequest.Files
から引っ張ってくる - Binaryを返す場合はActionResultに
File
を使って,octet-stream
とかで返す
お気持ち
TypedArrayをFormで送るとシリアライズされてくっそ長い文字列になるから非常に辛い.
これとWebDNNを組み合わせて使っているのですが,なかなか楽しい感じある.