眠いしお腹すいたし(´・ω・`)

C#関連を主に書きます。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

ASP.NET CoreでDI設定をappsettings.jsonに記述して設定してみよう('◇')ゞ

ごあいさつ

この前クルマ買い換えたんです。

その時にディーラーの営業さん(サーファー)に

ダム行くのに高速とか山道走るから性能のいいクルマが欲しいみたいな話をしたら・・・・

結婚の心配をされました\(^o^)/

そんなのとうに諦めとるわ、こらぁ(# ゚Д゚)

本題

最近のWebのUI周りのトレンドを勉強するためにASP.NET Coreを始めてみたら WebのUIに辿り着く前にASP.NET Coreで遊んでます。

このフレームワークASP.NET MVCより色々とよくできてると思います。

今のところ不満だなぁって思うところが見つからないです。

ASP.NET CoreはDIありきで作られているんですが

Unity(ゲームじゃない方)とかではweb,configとかUnity.configにRegisterの設定を記載してLoadConfigurationを呼ぶと設定どおりにContainerに登録されるような仕組みがあるのですが、ASP.NET CoreのDIにはないっぽいのです。

ですのでappsettings.jsonに設定を記載してconfigurationするプログラムを簡単に書いてみました。

まずはこんな拡張メソッドを作ってみます。

gist.github.com

appsetting.jsonから設定をオブジェクトで作成する部分はしばやさんの記事から

blog.shibayan.jp

ようするに

appsettings.jsonからRegisterSettingクラスを起こしてIServiceCollectionに登録している感じです。

Assemblyが指定されている場合にはAssembly.Loadを、指定されていなければ現在のAssemblyを使ってType型を手に入れています。

appsettings.json

gist.github.com

こんな感じで指定してあげれば良いです。

最後に呼び出しは

StartupクラスのConfigureServiceメソッドにて

gist.github.com

こんな感じで登録してあげればよい感じです。

ではでは( `ー´)ノ

ASP.NET Coreの学習帳

ASP.NET Core MVCの学習帳なのでちょっとずつ更新していきます。

GitHubでやれ、とのうわさがある。

プロジェクト構成

Staticなファイルはwwwrootフォルダに固まってる。 わかりやすくてよい( *´艸`)

jsとかcssファイルのbundleはbundleconfig.jsonにて管理するっぽい。 あまり調べてない。

project.jsonとかある。

以前に.net coreとかになる前に触ったときにあまり良い印象がなかったけど普通にnugetマネージャーで管理できてたのでそこまで苦労しなさそう。

なんかTool系のnugetパッケージはマネージャから追加したときにうまく動かなかった時があった。 コンソールからインストールしたらうまくいった。

設定関連

アプリケーションの設定はappsettings.jsonjsonとして追加していくみたい。

StartupクラスのIConfigurationRoot Configurationプロパティを経由して取得するようになってた。

  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }

ConnectionStringは専用の取得拡張メソッドが用意されてる。

  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=webapp1;Trusted_Connection=True;MultipleActiveResultSets=true",
    "StorageConnectionString": ""
  },

こんなのだったら

Configuration.GetConnectionString("DefaultConnection")

みたいな感じで取得できる。

自分で定義して取りたいようなケースには

  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }

からIncludeScopeを取得したい場合

Configuration.GetSection("Logging:IncludeScopes").Value;

で取得できる。

appsettings.jsonはStartupクラスのコンストラクタにて

var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                .AddEnvironmentVariables();
            Configuration = builder.Build();

こんな感じでビルドが行われている。

べつにappsettings.jsonってファイルじゃなくてもオッケー

AddJsonFileの二つ目が大切。

appsettings.xxxx.jsonというのでappsettings.jsonの中身を上書きしている。

env.EnviromentNameというのは環境変数ASPNETCORE_ENVIRONMENTにて設定される値らしい。

デバッグ環境のIIS ExpressではDeploymentと設定されている。

変えたければプロジェクトのPropertiesの下にあるlaunchSettings.jsonにて変更できる。

なので開発環境用、ステージ用、本番環境用にappsettings.jsonを分けて作成できる。

また、このセッティングのもう一つの特徴はappsettings.json以外でも環境変数設定にて指定可能なこと。

例えばappsettingsとかでは管理したくない本番環境の接続文字列とかは、その環境の環境変数に設定してしまえばよい。

ConnectionStrings:DefaultConnection みたいな感じで変数を作成して値に接続文字列を指定するとConfigurationで読み込まれている。

たぶんStartupのコンストラクタのAddEnvironmentVariablesがそれ。

パスワードとか秘密にしたいのは、シークレットなんちゃら、みたいな別の機構があるらしい。未確認。

DependencyInjection

そもそもFrameworkがDIありきで作られてる。すばらしい( *´艸`)

LifeCycleはSingleton/Scoped/Transientの3種類。Webなら十分。

Scopedはちゃんとリクエスト処理終了時にIDisposableならDisposeが呼ばれてたので安心して使える。

Startup.csのConfigureServices関数で注入するみたい。

ConfigureServicesの引数はIServiceCollectionなのだけど、このクラスに対する拡張メソッドが沢山用意されてる、

Loggingとかantiforgeryとか。

たぶん必要になったら追加したりするのでしょう。

設定ファイルからの注入が可能かは未確認。-> 確認したい。使うクラスを切り替えるのにビルドしなおす必要があるのは嫌だ。

ロギング

まだ調べてない。

O/Rマッパー

一般的にはEntityFramework Core https://docs.efproject.net/en/latest/を使うらしい。

Dapperは.NetStd1.3に対応していたので使える。

PetaPocoは www.nuget.org 対応してくれた方がいた。 ただPocoクラス作成のT4がなかったので(´・ω・`)なかんじ。

基本的には機能制限方向。コンスラクタがIDbConnectionを引数とする一択だった。

EntityFramework Core

Codefirst

DbContextを継承して各パターンはそのまま。

マイグレーションをするには

SQLServerにする場合には

を入れる。Toolsだけはコンソールマネージャから入れた。

Add-Migration hogeマイグレーションクラスが作成されて

update-database でマイグレーションできる。

マイグレーションするデータベースはDbContextクラスで指定したもの。 DbContextクラスの接続先をDIなどで注入する形をとっている場合、何かのルールで勝手にいい感じに注入が行われて開発環境にマイグレーションできる。

ASP.NET Coreプロジェクトの場合、Startupクラスで注入しているのであれば問題なく開発環境にマイグレーションされた。

ただこのことによってクラウド上の環境にマイグレーションする場合の方法がわからなかった。

もう少し仕組みを調べる必要がある。

DBFirst

調べてない。

クラス中のReactivePropertyに自動でSubscribeを仕掛けてみよう(*'▽')ノ

ご挨拶

全国何人かの皆様、超お久しぶりです。

ずっとさぼってました( `ー´)ノ

仕事でもプライベートでもXamarinはあまり触ってなくて、もっぱらクラウドデザインパターンのお勉強とAzureのお勉強などをしておりました。

Prism.Formsはちょっとしたアイディアを試すために少々触っていましたがMVVMフレームワークの必要性に関して疑問符が付く結果となってしまい記事にはできませんでした。

昨日JXUGのカンファレンス

eventdots.jp

がありまして、地方在住の私はyoutubeから見ておりました。

最近はあまり面白いプログラミングのアイディアがなかったり仕事の方も人間関係や職場環境によりモチベーションが保てなくてウジウジな生活をしておりましたがJXUGCの登壇を見ていてmoq(もっきゅ(*'▽'))というキーワードからやってみたいことを思いつきまして早速プログラムをしてみたので記事にいたしました。

果てしなく一般向けでない内容となっておりまして私自身もしっかりと理解できていない点もありますので御指摘等ありましたらTwitterの方にお願いいたします。

成長の為にも是非ともお願いいたします。

なお本日は休日出勤しなければならないので早く寝なければなりません(^^)/

本題

MVVMのViewModelにて値の変化をログ出力したりデバッグ出力するような場合、ViewModel自体にINotifyPropertyChangedが実装されている時にはイベントを仕掛けて出力やその他処理を行えばよいです。

しかしプロパティにReactivePropertyを用いている場合にはプロパティ個別にSubscribeする必要があるので状況によってはコードを書くことが面倒だったりします。

なのでクラス中のReactivePropertyにリフレクションを使って汎用的にSubscribeとかする事ができたらいいなぁ というのが今回のアイディアでありました。

がしかし

ReactivePropertyってGenericなんですよね。

Genericの場合、Reflectionでメソッド実行したりする事が難しかったり無理だったりすることが多いんですよね。

しかもSubscribeはIObservableの拡張メソッド・・・

当初はReflectionでサクッとできたらなぁと思っていたのですがどうやら無理そう・・・・

ReactiveProperty自体はINotifyPropertyChangedを持っているのでイベントを仕掛けてIReactivePropertyのValueプロパティからObject型の値をとるところくらいまではできるのですが、それでは発展性もなくてイマイチ(´・ω・`)

またアイディアを形にできないのかぁ・・・・なんて思っていました。

そんな中、ふと思い出したのがSystem.Expression 所謂式木です。

ufcpp.net

なんとなくはわかるのです。でもやっぱり難しい式木(´・ω・`)

以前O/Rマッパーのカスタマイズを少しやっていた時に式木に遭遇して多少は実コードを読んだことがあるのですが、やっぱり難しかったです。

でも、きっと、Genericなメソッドも式木を使えば呼び出せるのだろうと思い調べてみましたらこんな情報を見つけました。

tnakamura.hatenablog.com

なるほど、サンプルコードがわかりやすいのでなんとなく理解できた気がします。

このサイトを参考にして小一時間コネコネしてみましたらうまくできました。

完成コード

では実際にトライしてできたコードがこちらです。

gist.github.com

実行結果がこちら

f:id:tamafuyou:20161029011300p:plain

個別にReactivePropertyにSubsucribeを行わずに購読を行いコンソール出力を行うことができています。

解説します。

ReactivePropertyのみ抽出

vm.GetType().GetProperties()
                .Where(
                    x =>
                        x.PropertyType.Name.StartsWith("ReactiveProperty") ||
                        x.PropertyType.Name.StartsWith("ReadOnlyReactiveProperty"))

ViewModelのインスタンスからTypeクラスを取得しPropertyInfo配列を取得しプロパティの名前の先頭から文字列比較しています。

もっとちゃんと書けると思いますが、今回の主題でないので割愛です。

ReactivePropertyにSubscribeを行うメソッドを定義

public static IDisposable MySubscribe<T>(IObservable<T> source, string name)
            => source.Subscribe(x => Console.WriteLine($"{name}:{x}"));

渡られたIObservableとnameを使用してSubscribeを仕掛けてOnNext時にはコンソール出力を行うようにします。

購読を追加する

.Select(x =>
          Expression.Lambda(
                Expression.Call(typeof(Program), "MySubscribe"
                     , new[] {x.PropertyType.GetGenericArguments().First()}
                     , Expression.Constant(x.GetValue(vm)), Expression.Constant(x.Name)))
          .Compile().DynamicInvoke() as IDisposable)

PropertyInfoの配列に対してSelectを行ってその中でSubscribeをコールしています、

Expression.Lamda -> ラムダ式を作成するメソッドです。

引数には

メソッドをコールする式木を作成するExpression.Callを使用しています。

第1引数のtypeof(Program)はコンソールプログラムですのでメインプログラムクラスを指定しています。 第2引数にはコールするメソッド名を指定しますので先ほど作成しておいたMySubscribeの名前を指定します。 第3引数はメソッドがGenericの場合にTypeの配列を指定します。

今回はReactivePropertyのGenericの型を指定したいのでx(PropertyInfo)に対してPropertyType.GetGeneticArguments().First()とすることでGenericの型を指定します。

第4引数以降はparamsです。MySubscribeの引数を指定します。

MySubscribeの第1引数はIObservable 要するにSubscribeを仕掛けたいReactivePropertyを指定したいのでExpression,ConstantにPropertyInfo.GetValue(Instance)を渡して指定します。 MySubscribeの第2引数はプロパティの名前を渡したいのでExpression.ConstantにPropertyInfo.Nameを渡して指定します。

これでMySubscribeをコールするLambdaができますので .Compile()でラムダをコンパイルDelegateを作成します。 DelegateのDynamicInvokeを行い実際に作成されたメソッドを実行します。 戻り値はIDisposableですので as で変換してselectの戻り値とします。

これでクラス中のReactivePropertyに対してSubScribeを仕掛けることができました。

テストしてみる

            vm.StringTestProperty.Value = "test1";
            vm.IntTestProperty.Value = 10;
            vm.StringTestProperty.Value = "test2";
            vm.IntTestProperty.Value = 11;

            Console.WriteLine("SubscribeをDisposeします");
            disposes.ForEach(x => x.Dispose());

            vm.StringTestProperty.Value = "test3";
            vm.IntTestProperty.Value = 12;

            Console.WriteLine("おしまい");

結果を見るとわかる通り

ReactivePropertyの値を変更するとコンソールに出力され式木で作成したメソッドの戻り値であるIDisposableをDisposeすると購読が解除されコンソール出力されなくなります。

今回は単純にコンソール出力を行っただけなのですが、Subscribeを仕掛けるMySubscribe内にて色々することができるので例えばZipとSkipを使って変更前の値との同時に出力したり色々できるので夢が広がります。

本日は休日出勤なのでもう寝ます。

WatsonのSpeech To TextをXamarin.Formsで試してみたよ('◇')ゞ

音声認識の実装に関して興味があったのでWatsonのSpeech To Textを使用してXamarin.Fromsで音声認識を行ってみました。

www.ibm.com

なぜWatsonにしたか

GooleのCloud Speech APIが50回の回数制限があったから。

です。

Xamarin.Formsで音声入力を文字化する実装を考えたときにAndroidの方はSpeechRecognizerを使用すればできるんですが

developer.android.com

iOSの方がなかなか難しいんです。

最初はGoogle Cloud Speech APIを使って音声認識を試してみようかと思ったのですが使用回数が50/dayだったりでほんとにちょっとしたテストしかできませんでした。

ということで別の方法を探してました。

qiita.com

この記事を読んでいたら

Watsonは有料となっていたのですがサイトを見てみたら最初の1000分までは無料とのことだったので試すにはちょうど良いと思いWatsonを試してみました。

CMとかもやってますしねぇ。Watson。

www.ibm.com

登録とか

Bluemixのアカウントを作成します。

最初の30日は無料ですべてのサービスにアクセスできるみたいです。

Bluemixのアカウントを作成すると組織とスペースを決めます。

組織は日本語で大丈夫でしたがスペースは日本語だめかもしれません。

最初に日本語を入れてみたのですが、登録は成功するけど反映されないみたいなおかしな状態になったので英語にしたほうが良いかと思います。

ホーム画面からWatsonを選択します。

f:id:tamafuyou:20160605151600p:plain

右上の「+」ボタンをクリックします。

f:id:tamafuyou:20160605151759p:plain

Speech To Textを選択します。

f:id:tamafuyou:20160605152133p:plain

特に考えずに作成を行います。

f:id:tamafuyou:20160605152720p:plain

資格情報の作成を行います。

f:id:tamafuyou:20160605152912p:plain

usernameとpasswordは認証情報として使用します。

f:id:tamafuyou:20160605153150p:plain

APIについて

APIReferenceはちゃんと用意されています。

www.ibm.com

主にHTTPを使用したセッションありとセッションなしのAPI、WebSocketを使用したAPIがあります。

HTTPを使用したセッションは保存済みのデータをテキストに変換するのに適していてWebSocketはリアルタイムに変換する事に向いていると考えてよいかと思います。

Java用とnode.js用のライブラリは用意されています。

またUnity用のC#ライブラリもありますので、お手軽にっていうのであればそちらを利用するのも手です。

今回はAPIの理解を得たい面もあったのでそれらは使用せずに実装します。

リアルタイム変換を行いたいのでWebSocketのAPIをします。

実装

とりあえずソースコード

gist.github.com

Observer/Observableパターンで実装してます。

使用しているライブラリは

WebSocket-Sharp

www.nuget.org

Json.NET

www.nuget.org

認証

まずWebSocketで接続を行います。

接続URLはwss://stream.watsonplatform.net/speech-to-text/api/v1/recognize

クエリストリングにてmodelを指定できます。

modelは言語に使用する言語に対応した物を指定します。

今回は日本語ですのでja-JP_BroadbandModelを使います。

資格情報としてSpeechToTextの資格情報を設定します。

_client.SetCredentials(user, password, true);

そして接続を行います。

接続に成功した場合、クライアントからスタート情報をjsonで送信することで変換ストリーミングを開始できます。

            var startjson = JsonConvert.SerializeObject(
                new Connection
                {
                    Action = "start",
                    content_Type = $"audio/l16;rate={SampleRate};channels={Channel}",
                    InterimResults = InterimResults,
                    Continuous = Continuous,
                    InactivityTimeout = -1,
                    MaxAlternatives = 1,
                    Timestamps = false,
                    WordConfidence = false
                }, Formatting.Indented);
            Debug.WriteLine(startjson);
            _client.Send(startjson);
            _isSending = true;

今回はPCM音声データを使用しますのでcontent-typeにはl16を指定しrateとchannelsを追加で指定します。

Interim_resultsは変換が確定しない時点でもストリーミング的に途中結果を受け取ることができます。

continuousを有効にすることで断続した変換を行うことができます。

スタート要求を送信するとstate : "listening"というjsonを返答してくれます。

スタートを送信したらあとは、PCMデータをWebSocketのBinaryFrameにて送信することで結果を返答してくれます。

            if (!_isConnected) return;
            if (value.IsStop == false)
            {
                if (!_isSending)
                {
                    StartRecognize();
                }
                _client.Send(value.PcmStream);
            }
            else
            {
                _client.Send("{\"Action\": \"stop\"}");
                _isSending = false;
                Debug.WriteLine("Stop");
            }

結果に関しては Speech to Text Service Documentation | Watson Developer Cloudを読んでください。

受信処理は

                        var result = JsonConvert.DeserializeObject<SpeechResult>(args.Data);
                        Debug.WriteLine(args.Data);
                        result.Results.ForEach(res =>
                        {
                            if (res.Alternatives.Any())
                            {
                                var speechtext = new SpeechText
                                {
                                    IsFainel = res.Final,
                                    Text = res.Alternatives.First().Transcript
                                };
                                _speechTextSubject.OnNext(speechtext);
                            }
                        });

こんな感じで書くことができます。

今回はXamarin.Forms側のプログラムは説明しませんがソースコード

github.com

こちらで確認することができます。

精度的には他と比較していないので何ともです。

おそらく多と比較検討してくれる記事などを書いてくれる人が出てくると思うので期待です。

このように実装することでオンライン限定ですがクロスプラットフォームでの音声認識を実装できます。

このケースでは音声認識部分はAndroidiOSでコード共有率100パーセントです。

Xamarin素晴らしい。

以上です。

ToReactiveProperty拡張メソッド

特に書くことがないのでReactiveProperty使うときに追加している拡張メソッドを紹介します。

gist.github.com

ToReactivePropertyAsOneWaySync

ModelからReadOnlyReactivePropertyを作成するときに使います。

むっちゃ使います。

INotifyPropertyChangedクラスからViewModelのプロパティ作成するときはまずこれです。

基本はViewModelのプロパティは基本がReadOnlyReactivePropertyでありReadOnlyObservvableCollectionでありReadOnlyReactiveCollectionです。

編集が必要な時のみReactivePropertyを使ってます。

ToReactivePropertyAsOneTime

たまに使います。

ReactiveProperty.FromObjectを使いたい時によくなんだっけ?って忘れるのでToって書けばインテリジェンスで候補が表示されれば幸せになれると思います。

IDisposableとusing

今更なんですけどC#初心者な感じの話です。

最近ReactiveExtentionsを勉強しててDisposableによく触れるのですが自分でDisposableを実装するってやった事なかったなぁと思ってちょこっと作ってみました。

gist.github.com

よくあるtry catchパターンの代替としてusingを使用する例です。

DisposableにてCommitするかRollBackするかを制御しています。

もっと色々なパターンでIDisposableって活用できそうですよね。

IObservable/IObserverもそうなんですけど,.NET Frameworkで用意されているInterfaceって色々と意味があるんだなぁと再認識させられます。

.NETってデザインパターンの見本になるしオブジェクト指向を勉強するのにすごく良いんだなって思いました○

NSpeex.Reactiveをリリースしてみました

この度

www.nuget.org

NSpeex.Reactiveというライブラリをリリースしました。

現在のバージョンは0.0.1です。

このライブラリはNSpeex

nspeex.codeplex.com

と、NSpeexをObserver/Observableな感じで使用するための余計なライブラリが含まれています。

NSpeex単体で使いたい場合は本家を使用してください。

NSpeex単体でnugetパッケージを作らなかったのはワザとです(^◇^)

このライブラリは.NET4、Xamarin.Android、Xamarin.iOSで利用することができます。

github.com

にて管理を行っています。

どんなライブラリ?

こんなライブラリです。

NSpeex - Speex for .Net and Silverlight - Home

プラスしてRxのサブジェクトっぽくNSpeexを使えるようにしてあるだけです。

強いていえば、XamarinでNSpeexが使えるよ(^◇^)っていうのが特徴です?

サンプルは?

すいません。間に合っていません。そのうちサンプルアプリを作ろうと思います。

コードのイメージはこんな感じです。

gist.github.com

どっかで見た気がします。

ObservableVoiceCaptureでキャプチャしたPCMをNSpeex.Reactiveでエンコード・デコードした後にDelayを1000msecかけて再生している例です。

どんなことに使えるの?

PCMデータをSpeexでエンコードしてネットワーク経由で送信して受信してデコードして再生するとVoIPになったりします。

現在の新しいVoIPなコーデックといえばOpusなのですが、Speexだってレイテンシも悪くないしイケてると思います。

たぶんそのうちOpusのライブラリ作ると思いますけど(^◇^)

おまけ

NSpeex/src/NSpeex.TypeScript at master · yuka1984/NSpeex · GitHub

以前のエントリー Netjsを使ってC#からTypeScriptへの変換をしてみた。 - 眠いしお腹すいたし(´・ω・`) で紹介したNSpeexのデコードの一部(NarrowBandにのみ対応)をTypeScriptで使用できるようにしたライブラリはこちらに管理を移動しました。

一応ブラウザで動かす例をちゃっかり載せときます。

gist.github.com

サンプルはWebSocket経由でSpeexエンコードされた音声データを受け取ってJSにてデコードしてWebAudioAPIを使用して再生している感じです。