CoreCLRなBlackJumboDogにするとき仕組みを変更した理由と言訳 動的読み込みから組み立てに

前日からの続きです。日本各地で雪もすごい中、こんながあったりと。個人的にこれ賛成です。ASP.NET5って名称いつまでたっても、.NetFrameworkが5にならないか、いきなり6にいくかとかそういう偶数と奇数みたいなことでもしないとバージョン明記だけは無理があると思ってました。ただまぁ、次世代をいく、置き換えていくっていう願いが込められていたのではないかと思ったりもします。そこで、.Net Coreと同じようにCoreってつけたのいいと思いましたよ!名前と仕組みも一致した感じで。

.Net Core

以前、BlackJumboDogをはじめたところの記事でも書いていますが、GACとかってないんですね。基本すべて、NuGetからダウンロードなんですね。NuGetの参照って、名前とバージョンのみなんですが、これの実体となるDLLは、プラットフォームによって異なることが許されている。つまりDLLは動く環境によって変わる。言い方を変えると、DLLを参照するんじゃなくて、この名前を与えられているパッケージ(バージョンも指定可能)を必要としますっていう感じなんですよね。そうするとプラットフォーム用の実体が自動的に選ばれますよって。何を言いたいかというと、そもそも、実体のDLLに依存したものっていうのが静的(コンパイル)にはできない。また、参照として追加したいなら、DLLの形では難しいということなんですね。今はプロジェクトを参照する形で実現しているのが最初その違いに気づくのに時間がかかりました。NuGetだったので、ASP.NETみたいに、どっかにDLLあってみてるんだろーくらいに思ってたんですね。実行しているときはそうなるわけですが、コンパイル時には見てないってことをちゃんと理解していなかった。。。DLLとかライブラリ作ったならどこかで組み立てるプロジェクトがいないと話にならないなぁって思ったんですね。そこで、Bjd本体と実行イメージを作るプロジェクトを分けてみた(Bjd.Common.CoreCLRとBjd.CoreCLR)という結論を出してみました。これは、将来、BjdがNuGetに上がったりしたときに、利用する側がASPNETホストであるkestrelを動かすのと同じ感覚になることをイメージしてます。

そして、プラグインとしてDLLをReflectionを用いて拾い上げてプラグインを検索していたものを、ランタイム上に読み込まれているものからプラグインを検索する方法にしたというところでした。これはIssuesを見つけるまでどうしたもんかとひたすらネットサーフィンしてました。ここのServiceProviderっていうのを利用して、LibraryManagerなるものを取得、そこからプラグインを検索しています。できてしまえば、大したことないんですけどね。

こうして記事書きながら改めて振り返っているうちにEntryPointExecutor.csからActivatorUtilities.csを経由してMainは初期化されていく様子だということがわかったり。ServiceProvider.csという実体が見つかったりと、いろいろ面白い発見があったりするため、かなり楽しんでいます!ただ、この記事に書いている内容はソースをベースに話を進めているので、将来に渡っての仕様として明確なことではありません。ご了承ください。

それではまた!

CoreCLRなBlackJumboDogにするとき仕組みを変更した理由と言訳 System.Windows.Forms

こんにちは。BlackJumboDogの置き換えに着手して1か月近くが経過しました。そこで、近況ばかりだったここに、当初大きく変更した点を記していきます。自分のまとめと疑問が含まれていますので少し脱線する要素は多くなります。また、答えを求めていた方にはそぐわないものになるかもしれないことを、あらかじめご了承ください。

本家BlackJumboDog

Bjdというプロジェクトがすべての基本となる機能を持っていました。それはExeでWindowsFormsのGUIを持っていました。GUIは起動すると最初に表示されサーバーの設定もログもWindowsサービスのセットアップもこれ一つできるというオールインワンの仕様です。お手軽さとして非常に大きく価値あるものだと思っています。勝手ながらこの記事では、これをBjd本体と表現することにします。

次に、サーバーの機能は参照する他のプロジェクトで実装されていました。ここに実装された設定は、自動的にGUIを追加する機能をBjd本体が提供していました。また必要に応じてダイアログを追加するような土台もBjd本体が提供していました。サーバーの通信処理(Socket)もBjd本体が多くを提供していました。実装は設定と通信プロトコルに集中したものです。勝手ながらこの記事では、Bjdサービスと表現することにします。

Bjdサービスのプロジェクトは、コンパイルによってDLL(アセンブリ)となりそれらを所定のディレクトリに配置しました。実行時には、その特定名称となるDLLを自動的に読み込んでいました。このときに使っていたのがリフレクション(System.Reflection名前空間にある機能)です。このリフレクションとは、型に厳密であるC# VB.NETなど.NetFrameworkの言語に対して、実行時における動的な処理を追加する機能です。コンパイル時にはないものを実行することができる反面、実行するまで結果はわかりません。

アセンブリは通常ファイル名またはアセンブリ名を指定して読み込まれていきます。GAC(GlobalAssemblyCache)はその一つです。これは署名されたアセンブリでインストールされたものだけが格納されている特別な領域です。.NetFrameworkを使ったことのあるかたはご存知のSystem、System.Data、System.Netなどのアセンブリはここに格納されています。これらに格納されたアセンブリを参照したアセンブリで実行イメージを作った場合。実行イメージである.exeと同じディレクトリにアセンブリファイルが存在する必要はありません。サードパーティ製のアセンブリもここにインストールされていることもあります。サードパーティ製のものを使って実装したものが、違う環境では動かなかった。そんな経験を持っている人はかなり多いんじゃないか?と思います。その場合は、このGACに同じものが入るようにインストールするか、コピーしたアセンブリ(DLL)をExeと同じディレクトリに配置する必要がありました。これは、VisualStudioのプロジェクトの参照設定でいう「ローカルコピー」というやつで実現できました。

さて、少し長々と書きましたが、上記の構成では、CoreCLRで動く.Net Coreではいくつか難問がありました。

System.Windows.Formsは存在しない

実は、、、.Net Coreには存在してません。便利だったこのGUI(実際これ肝だったと思う)は削除することにしました。ただし、こうすることで、構成の変更はどうやってやるのか?という話になってくるかと思います。これは、元のBjd本体で作ったoption.iniをそのまま使えることを前提として、この機能を削除しました。ログはファイルに出力されますので、直接の問題にはならないでしょう。CoreCLRはプラットフォームを選ばないものとして作られているため、将来的にもこれが提供される可能性は低いのではないかと思います。あくまで個人的見解ですが・・・。そのまま動かすというのであれば、Monoという.NetFrameworkのCross platformなものがあります。それを選べばいいわけです。こんなところで、CoreCLRを選ぶからこそのメリットを明確にしていく必要が出てきたわけでした。

(続く)

 

 

NUnit dnx – BlackJumboDog CoreCLR

こんにちは!前回は、xUnitどうだろうか?ということで検討していましたが、そもそもNUnitがdnxに対応してました!

NUnit 3.0.0 Release Candidate – November 1, 2015

Framework

  • The portable build now supports ASP.NET 5 and the new Core CLR.NOTE: The nunit3-console runner cannot run tests that reference the portable build. You may run such tests using NUnitLite or a platform-specific runner.

ので、移植をメインとして挑んでいくことにします!(早くデプロイしたいという気持ちが抑えられないわけではないと自分に言い聞かせる)また、注意事項が、Upgradingに書いてありました。

For example, NUnit 3.0 no longer supports ExpectedExceptionAttribute. However, preferred alternatives Assert.Throws and the ThrowsConstraint have been available for several years. If you remove the attribute from your tests and use one of the alternatives instead, you can verify that they work in your present environment and they will continue to work after conversion.

ExpectedExceptionAttributeはサポートされなくなったようです。代替として、Assert.ThrowsNUnit.Framework.Constraints.ThrowsConstraintがあるとのこと。うーん。属性によるサポートはなくなったよーみたいなことかなぁ。Exceptionの挙動は、UIスレッド(クラシックWindowsFormなApplicationException)とかAppDomain(UnhandledExceptionあたり)も絡むので、CoreCLRAppDomainの概念はそもそもないと宣言されてる。System.Windows.Formsは存在しない。どちらもないと思われる。)だとつらいとか、実は制約多いからなんかわからなくもない。VSCodeにも.Net Coreにも対応していくなら当然な流れともいえる気がします。というわけで、そのあたりも置き換えていきます! “NUnit dnx – BlackJumboDog CoreCLR” の続きを読む

Ubuntu上のAsyncで遅延 – BlackJumboDog CoreCLR

ずーっと気になっていたんですが、Ubuntu上でサーバーのTCPソケットをAcceptAsyncかけていたら、しばらくアクセスがない状態だと1秒程度の遅延が発生していました。そして、連続したアクセスだとこれは起きなかったんです。

元々のBjdではWhileとSleepによるポーリングを行っていたので、おそらくそんなことは起きなかっただろうと思っています。(そもそも、Begin/Endが動かなかったので、根拠はない!)

同じことが、ManualResetEventSlimeでも起きました。ある程度時間がたったときに、シグナルセット後のWait解放が1秒くらい。これ、Windowsでは起きなかったんですよね。

正直、そこまでプラットフォームに詳しい人間ではないので、なぜこうなるのか?は理解できませんでした。ただ、どうすれば?に関しては、「深い眠りにつかないようにする」っていう発想で回避しました。

https://github.com/darkcrash/bjd5/commit/a9049f8630d2e788dda19065026c415654efcd05#diff-c042d296432145429c9f5f4d27bfef99

     -            tTcp.Wait(this.Kernel.CancelToken);  
 94   +            while (true)  
 95   +            {  
 96   +                if (tTcp.Wait(2000, this.Kernel.CancelToken))  
 97   +                    break;  
 98   +                if (tTcp.Status == TaskStatus.Canceled)  
 99   +                    break;  
 100  +            }

Waitを2秒までとして、完了時はループを抜け、キャンセル時もループを抜けます。こうすることで2秒に一回このWaitが実行されます。そして、結果として遅延1秒はなくなりました。

SpinWaitの絡みとか、タイムスライスのルールとかありそうなんですが、ブラックボックスです。Darkが作るBlackなだけに・・・

これが、Kernelによるものなら、今後もこういう仕様ということになるでしょうし、.Net Coreのものであれば、改善されていくかもしれません。ので、現時点ではこのコードは、一つの回避策として整理してくださいませ!

それでは!

BlackJumboDog on CoreCLR を.NetFrameworkで動かそうと思ったら・・・

ツイッターで、.NetFramework4.6で動かして、NUnitどうなの?という声をいただきまして、さっそく!project.jsonに以下を追加してみました。

  “frameworks”: {
“dnxcore50”: { },
“dnx461”: { }
}

う・・・。いやな感じに。

というのも、このSystem.Text.Encodingを含めは、23516で統一していたのですが、.netframework4.6では、どうやら違うバージョンになさいとのことです。バージョンを厳密にした思わぬ落とし穴でした。

(というか、、、少しおかしい気がします。機会があったらこの辺調べてみようかとは思います。dnx461でそもそもいいのとか。)

これを、それぞれのフレームワーク用に整えていけばよいのですが、今回の目的は、.NetFrameworkでも動かす!ではなく、テストの簡略化にありましたので、別の案を考えたほうがよさそうなところでもあります。

ただ、テストコードは、アプリケーションさえたたいてしまえばよいわけで・・・テストコードの結果さえ得られればよいわけで・・・という風にも考えられなくもないですね。

「NUnit dnx」とかぐぐっていたら、こんなものもありました。

https://github.com/xunit/dnx.xunit

Getting Started with xUnit.net (DNX / ASP.NET 5)

ちょっと興味が出てきます!これをNUnitのコードから移植してとかっていうのも面白そうですね!

(つづく

BlackJumboDog CoreCLR Ubuntu – Socketの置き換え APMからTAPへ

こんにちは!いきなり動いてるスクリーンショットから!!(Azure上のUbuntu14.04で動かしている様子です。)

というのも、動いてるだけでもすごいっていう気持ちを伝えたかったわけですが、今回に至るまでに行った変更点

  1. System.Net.Socketsのバージョンを他と統一し「4.1.0-beta-23516」としました。
  2. それに伴って、APMの実装は捨てられたため、TAPに書き直しました。
  3. パスの置換(\→.Netが提供するCharフィールド)を進めて動かしてみたところ、パスの置換が空回りして無限ループ!→修正済
  4. CPU利用率が起動直後で安定していても、10%以上という状況で、Thread.SleepをManualResetEventSlimに置換→アイドル中のレスポンスに1秒の遅延が発生。→検討中
  5. ConsoleTraceListenerの負荷がかかりそうなので、専用のタスクスケジューラ実装
  6. ログをそれっぽくフォーマットしました。

前回記事の、Begin/EndなどのAPM(非同期プログラミングモデル)なソケット実装がないとエラーになってました。これは、上のリンク先の通り、廃止されていくようです。このIssues(上と同じリンク) でその理由が書かれていました。Windowsに依存したようなものは排除する!っていう面白い話ですね。

ただ、これ変えてしまうと、そもそもポーリングしてるロジックとか全部作りなおしなわけで、結構時間かかってました&まだ懸念点が残ってます。行き詰っていろいろ試したのもあって、ソースの履歴が激しいことになっていてごめんなさいというところです。

また、ぜんぜん気づいていなかったのですが、Traceで出力したものは、Defaultのlistenerか何かによってだとは思いますが、しっかりとSyslogに出力されていました。(これはちょっと驚いた)

大物のWebServerが動いたので、懸念点を解消しつつデプロイ方向にシフトしていきます。

それではまた!

環境によるパスの違い – BlackJumboDog CoreCLR

前回から、Option.iniが読めてないのは見事的中しました。

https://github.com/darkcrash/bjd5/commit/789b737402a8e16b4d99147c6471eb83a426fce3?diff=unified#diff-e8a8a3be0e352480bc87c1f17ebc86bb

Windowsでは「\」をパスに利用しますが、Linuxでは「/」を利用します。ここにリテラルで「\」があったために、パスを拾えていなかったようです。これは、System.IO.Path.Combineメソッドを利用して対処しました。

でも、なんでこれで大丈夫なのだろうか?

という疑問が出てきましたので、ちょっとだけソースを追いかけてみました。

こうした環境の違いがあるために、.Net CoreのライブラリではPlatformによる違いを吸収する方法をとっているようです。

これが、Bjd(アプリ)が直接利用しているPathクラスの中身。(正確なバージョンまでは未確認。きっと多分)

System.Runtime.Extensions System/IO/Path.cs

中では「DirectorySeparatorCharAsString 」というフィールドを利用して、結合していますが、この実体はここにいません。

分割クラス(partial)となっており、

System.Runtime.Extensions  System/IO/Path.Windows.cs

System.Runtime.Extensions  System/IO/Path.Unix.cs

という風に複数定義されたものがありました。Unixでは「/」Windowsでは「\」(エスケープのため2文字なだけ)となっています。

これは、以下のプロジェクトファイルでターゲット($(TargetsUnix)、$(TargetsWindows))による切り替えが確認できます。

System.Runtime.Extensions.CoreCLR.csproj

つまり、プラットフォームごとに作られているものが違うということですね。

 

でも

2016-01-09 (1)

 

こ、今度は、BeginReceiveがないですと!!ポートが使われているよーはサービスを止めればよいとして、Windowsでは動いてるのに!!これも追いかけていこうじゃないですか!

それでは、また

 

 

Ubuntuで動いた!? BlackJumboDog CoreCLR

まずは無事に、動きました!DNX_TRACE=1から直接問題を検出できたわけではないですが、これを見ることによってどこまで動いているかの見当をつけることができたのは、StackOverflowExceptionのStackTraceを見れるのと見れないの違いくらいあるんじゃないかと思います。

2016-01-09

原因は、Consoleのサイズ取得もしくは変更をしようとしたところにありました。これは、本家Bjdにはない機能でした。GUIを捨てるときにどうしても何か見えるものをCUI上に出しておきたいと思ったのがきっかけです。Trace.Writeでトレースを出力するようにして、それをConsleに出力するためのTracelistenerを実装しています。

GitHub変更点

https://github.com/darkcrash/bjd5/commit/b42c4386866db1f681bbec13b6c20547b02e3320

Windows動かしている分には、サイズ変更できていましたが、SSH経由でそれをやると例外が発生していたようです。TryCatchを入れConsoleに出力したところメッセージが出てきましたので、取得または変更で間違いなさそうです。これもLinuxのGUI上からやったらどうなるかとかはわかりませんが、そんなことするなよって話もありつつ、やるならできない場合を考慮する必要があるようですね。

そもそも、何よ!って人に向けて

MSDN ライブラリ TraceListener クラス

これは、.NetFrameworkに昔からある機能で、Traceクラスを用いて、Writeメソッドやら、WriteLineとかで出したものを、受け取って何らかの処理をする機能を提供するための基底クラスです。ただ、.Net Core としても、Windows (ETW) があるようなので、Linuxでも動くならそっちのほうがよいでしょうね。

スクリーンショット見ると、サーバーは何も起動した形跡がないというオチが待っていました!おそらく、Option.iniを開けてとかその辺じゃあないのだろうかと思っていますが、本当に動くようになるまで戦いは続きます。

それでは、また!

 

 

 

 

 

Ubuntu dnxでTraceを出力する方法 – BlackJumboDog CoreCLR

前々日から、前日に続き

BlackJumboDogをUbuntu上で動かすために、いろいろ試行錯誤しています。どうやらUbuntuで動いていないのは本当に何か環境固有の問題ではないかと疑っています。

がしかし、何もエラーが出ずに困っていました。

そこで・・・

 

Creating a Cross-Platform Console App with DNX

https://github.com/aspnet/Home/wiki/Environment-Variables

 

ということで、環境変数を入れておけば、もっとトレース出すよ!ってことみたいです。ほかにもいろいろ変数があるようですね。

さておき、変数を設定して実行してみます。

env DNX_TRACE=1 dnx run

 

エントリポイントは再びお引越しして、bjdコマンドを定義してるので以下のように

env DNX_TRACE=1 dnx bjd

2016-01-07

何やら出てくるではありませんか!!

これをWindowsのものと比較してみます。

2016-01-07 (1)

 

アプリケーションが出すConsoleメッセージの直前は同じアセンブリを読んでるっぽいメッセージになってますね。

こうなると、PG側が悪いのではないかという疑いが出てきました・・・・!

ちなみに、UbuntuはAzureのもの使ってます。

明後日に続く!

VisualStudio がやっているdnxをLinux向けに置き換えるメモ2

前日に続き

まず、現状はうまくいっていません。ごめんなさい。

で、そもそもWindowsでもコマンドから実行させることができていない。VisualStudioで動いているからうごくもんだと思ったけど、そういうことではなかった・・・。

ので、Linuxの前にまずはWindowsのcmdからキックできることを目指すことにしました。

 

2016-01-06 (3)

ひとまず、program.csをエントリポイントとなっているアセンブリというかプロジェクトに移動させたところ動いたっぽい!いいんじゃないのいいんじゃないの!?

Ubuntuにもいっとこう!

明日に続く!

 

cheap mlb jerseys wholesale nfl jerseys cheap mlb jerseys wholesale nba jerseys