窓を作っては壊していた人のブログ

提督の窓や成績の窓を作ってました.今では適当に好き勝手に開発をしてます.

ASP.NET Core MVC + Razor Pages環境下でajaxでバイナリのフォームをPOSTしたりする時に行ったこと

備忘録です.

現在研究の一環で音声を使った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とかで検索してみると,こんな記事が見つかります.

www.talkingdotnet.com

このページを読むと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を組み合わせて使っているのですが,なかなか楽しい感じある.

仙台IT文化祭でMobile Center(現App Center)について発表してきました

2017年10月28日,29日に開催された仙台IT文化祭でMobile Center(現App Center)について発表してきました.

2017.sendaiitfes.org

タイムスケジュールを見ると私の名前は一切ありません. さて,どういうことか.こういうことです.

はい,前日の深夜に決まりました.

ということでちょまどさんのセッション内で10分程度の時間をいただいて発表することになりました. ちょまどさんのセッションはMobile Centerが一体どういうものか,どういう機能があるかといったものを説明するものでした. 自分もそこそこ使っているつもりではいたのですが,テスト関係の内容だったりは全く使っていなかったこともあり非常に興味深い内容だったと記憶しています.

で,自分の発表内容ですが,作成していた学祭アプリでMobile Centerを導入した結果Analytics機能を利用したことによりアンケートなどの集計サーバーを必要としないサーバーレスなアプリケーションが実現できたこと,またそれにより詳細なユーザーのセグメントが取得できた,そしてMobile CenterだけでなくAzure CDNやBlobも利用することによりで画像の高速な配信が可能になったことについて発表しました.

使用したスライドですがわけありで現在公開できないので,実際に作成した学祭アプリに関しての記事でそのことにも触れて紹介したいと思います.

ちなみに学祭アプリは

東北大学祭2017を App Store で

69th東北大学祭 - Google Play の Android アプリ

こんな感じでリリースされていて

github.com

またこんな感じでソースも公開しています.

.NETStandard2.0で作成されたXamarin.Formsアプリで,リポジトリパターンやユースケースに分けて作ってあるので,今後何かのカタログ情報を表示するようなアプリのいい感じのテンプレートになるんじゃないかと思っているので,ぜひともソースを見てみていただければと思います.

さて,いつ学祭アプリの話を書こうかしら...

XamarinなどのPCLプロジェクトにSystem.Reactiveを導入しようとすると失敗することへの対策

はじめに

今日Twitter

System.Reactive を PCL に追加するとエラーになる

といった内容のツイートを見かけました. 自分は過去に普通に導入できていたので何が違うんだろうなぁということで少し検証してみました.

検証環境

  • macOSX
  • PCL 4.5 - Profile 111 (Visual Studio for MacでPCLのプロジェクトを作ると作られるデフォルトのやつです)
  • System.Reactive 3.1.1 (現時点でのStable)

検証

とりあえず実際にSystem.Reactiveを導入してみましょう. するとインストールに失敗するはずです.まあ何かに失敗したらログを見ればいい解決手段が載っているはずですね. ということで少し眺めてみると

Could not install package 'System.Runtime.InteropServices.RuntimeInformation 4.0.0'. You are trying to install this package into a project that targets '.NETPortable,Version=v4.5,Profile=Profile111', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.

みたいなエラーが出ていると思います.これがSystem.Reactiveが導入できなかった根本原因と考えても良さそうです.

それであれば System.Runtime.InteropServices.RuntimeInformation 4.0.0 ではない,もうすこし上のバージョンではどうかと考えるのが基本的な考え方です. 実際にNuGetのサイトをアクセスしてみると

www.nuget.org

Stableで4.3.0が出ています.

依存ライブラリを比較してみるとバージョンアップの他,今回PCLのプロジェクトに影響しそうな部分で

Microsoft.NETCore.Platformsのバージョンが.NETCore 5.0の部分では1.1.0に上がり,.NETStandard 1.1の部分では削除されています.

ここが非常に匂いますよね?

GitHubのIssueを探してみると

Microsoft.NETCore.Platforms doesn't install on packages.config based projects · Issue #8952 · dotnet/corefx · GitHub

こんなものも見つかったりします. これが本当の原因であるかは(自分の知識が足りないので)わかりませんが,確かにMicrosoft.NETCore.Platforms 1.0.2でも導入に際してエラーが起こったのでこれであると断定してもいいでしょう.

ということで根本的な原因がわかりました.

あとは解決手段としてその問題が解消されている System.Runtime.InteropServices.RuntimeInformation 4.3.0 をまずはじめに導入します. System.Reactiveのインストールで失敗をしたSystem.Runtime.InteropServices.RuntimeInformationが入ってしまえばこっちのもんです,どうでしょう,入りましたよね?

問題の一つが解消されたのでSystem.Reactiveを導入してみましょう. 問題なく導入されたと思います.

まとめ

System.ReactiveをPCLのプロジェクトに導入する際はSystem.Runtime.InteropServices.RuntimeInformation 4.3.0 をまずはじめに導入すればよいでしょう.

またNuGetを使用してライブラリを導入する際はぜひともエラーログを見てみみてください. そうすると解決手段が結構簡単に見つかったりします. 最近ではXamarin.Android.SupportPackage関連でも同様の問題を抱えている人がいましたが,それはエラーログのAndroid71に対してのパッケージはないよー的なことが書かれていたので,TargetPlatformをAndroid80にすればいいだけだな,という風に容易に察しがつきました.

よくわからなかったら適当にバージョン上げてみるのもいいのかもしれませんw

おきもち

今回の問題が起きたのはXamarin StudioからVisual Studio for Macとかに変わってMonoのバージョンが4.8から5系に変わったり,もしくはインストールされている.NET Core SDKのバージョンが上がったことによって起こった問題ではないかなぁともちょっと想像しています.

Mono4.8から5系ではビルドシステムのフローが変わった気がしますし,.NET Core関係でも1.0.1-preとかのときと最近ではまずパッケージ管理の方法が変わったりしましたし,そういうものが積み重なって今回みたいなケースが出たんじゃないかなぁ...違うかなぁ...

ということで昔の環境を持っているという人は是非試してみて欲しい案件ではありますねw

Xamarin WorkbooksがOSSになったので早速コントリビュートしてみた

Microsoft Connect(); 2017 Day1の興奮冷めやらぬまま朝起きたら

えっ,マジで!?Xamarin Workbooksのソース見れるの!?と朝から更に興奮させる出来事が.

早速Cloneしてビルドし実行してみると,そこには自前ビルドのXamarin Workbooksが. 今まで使い続けてきてどういう仕組なんだろうなぁ,とか,オレオレビルドなんだけど?とか言ってみたいなぁと思っていたので感動もひとしおです.

ここまではいいのですが,一点気になることがありました. いつからかのビルドから,Alpha版などではたぶんNuGetパッケージを追加するであろうボタンが真っ黒になっていました.f:id:yamachu_co:20171116204724p:plain

これおま環って言われるやつなのかなぁとすごい心配&どこにバグ報告すればいいのかわからなくてずっと悩んでいましたが,手元にはソース,ハックするしかないですね.

ということでハックを開始し原因がわかったので早速PR

[UI][mac] Remove background color to show NSAddTemplate by yamachu · Pull Request #97 · Microsoft/workbooks · GitHub

ひどい英語でもスクショあれば大丈夫だろうと信じポストしたら環境などを聞かれ色んな調査が始まりました. 原因としてはXcode9系からのバグ(?)だそうで,タイムリーなものを引き当てたようです. こういうバグにすぐに出会えるのもAlphaチャンネル運用の醍醐味でもあります.

ということで対策としてはありな修正だったようで無事マージとなりました.

その後ツイッター

非常に嬉しいですね.

オープンソースのプロダクトはこういう風に仕組みを知れたり,実際に自分で手をいれることが出来るので非常に勉強になります. これからもこういう活動は続けていきたいものです.


頑張って英語考えて返信してみた.久しぶりの英文であれ,仮定法みたいなやつってあとのやつは過去形だっけ?とか悩みまくったレベルに英語力落ちた

Xamarin.Forms 2.5.0 がリリースされました

Release 2.5.0 · xamarin/Xamarin.Forms · GitHub

今回は全然気づかなかった...コミットを見ている限りAndroidのRenderer関係(2.4.0から導入されたFast-Renderer周り)のコミットが積まれていたり, iOSに関してはバグフィクスがメインに見えましたが,本命としてはEmbeddingかなと思います.

これに関しては自分がちゃんと書けそうであれば記事にして,無理そうなら他の方の記事を引用しようかなと思います.

ちゃんとしたリリースノートがまだ出ていないので(11月16日午前3時現在),積まれたコミットからお送りしましたー

リリースノートが出ました

Xamarin.Forms 2.5.0-stable - Xamarin

また同時にNuGetから落とせるようになっているようです.

Mobile Center あらため App Center を使ってみた

もともとMobile Centerを使っていたプロジェクトのパッケージを変えてみました.

github.com

こうやってDI出来るような形にしておくと変更箇所が非常に少なくなるのでいいですね. 実際に動作させてみましたが,特に変わりなくそのままの変更で利用が可能でした.

このアプリケーションについては近日Mobile CenterあらためApp Centerを使っていい感じになった的な記事を書くのでおまちください...

私の使う範囲では無料で利用が可能なのでこれからも使い続けたいと思います.

料金関係は簡単にまとめてくださった方がいるので,こちらを御覧ください

ytabuchi.hatenablog.com

t.co

うーん,仕事が速いなぁ


くぅ君のブログにPush通知関係のことがあるのですが,5セグメントであるという風に判断したのは,ドキュメントを読んでいてバックエンドはFirebaseだろうなぁと思ったからです.

でソースを見てみたら...

github.com

うん,ビンゴっぽそうですね


ですが昔作ったプロジェクトのせいなのか,それともApp Center側の内部APIのBase URLが変わっていないのか,AnalyticsのデータなどがWebのインタフェースから見れなくなっています...さてまたAPIを叩いて確認するしかないかなぁ.

Visual Studio for Mac 7.3.0.764 がリリースされてます

まーたAlpha関連の話です.

Release monodevelop-7.3.0.764 · mono/monodevelop · GitHub

悪い子なのでURL直叩きで落としてきてしまったので,いつ一般的に配信されるのかわからなかったのですが,ついさっき

  • Xamarin.Android 8.1.0.23
  • Xamarin.iOS 11.4.0.214
  • Xamarin Workbooks and Inspector 1.4.0-beta1

がアップデータで振ってきたのでたぶんこれと同時に落ちてきたんでしょう.

Xamarin.iOSに関してのお話で,StableではXcode 9.1に対応していましたが,Alphaでは対応されていませんでした. しかしXamarin.iOS 11.4.0.214から対応になったので,AlphaユーザーはXcode 9.1にしていた場合アップデートをおすすめします.