|
検索
リンク
タグ
Plone
統合Windows認証
Ruby
ADO.NET Entity Framework
NUnit
ASP.NET MVC
ライトニングトーク
ASP.NET
Selenium
C#
LINQ
.NET
F#
SQL Server
Visual Studio
Fizz-Buzz
WebMatrix
jQuery
AJAX
Haskell
カテゴリ
最新のコメント
最新のトラックバック
以前の記事
2011年 12月
2011年 11月 2011年 10月 2011年 09月 2011年 08月 2011年 07月 2011年 06月 2011年 05月 2011年 04月 2011年 03月 2011年 02月 2011年 01月 2010年 12月 2010年 11月 2010年 10月 2010年 09月 2010年 08月 2010年 07月 2010年 06月 2010年 05月 2010年 04月 2010年 03月 2010年 02月 2010年 01月 2009年 12月 2009年 10月 2009年 09月 2009年 07月 2009年 06月 2009年 05月 2009年 04月 2009年 03月 2009年 02月 2009年 01月 2008年 12月 2008年 11月 2008年 10月 2008年 09月 2008年 08月 2008年 07月 2008年 06月 2008年 05月 2008年 04月 2008年 03月 2008年 02月 2008年 01月 2007年 12月 2007年 11月 2007年 04月 2007年 03月 2007年 02月 2007年 01月 2006年 12月 2006年 11月 2006年 10月 2006年 09月 2006年 08月 2006年 07月 ファン
|
2011年 12月 15日
この記事は Windows Azure Advent Calendar jp: 2011 の15回目です。
←前回 @normalian さん「Windows Azure の大幅更新 ~Node.js編~」 →次回 @orz_yuki さん はじめに前回の投稿で、「正規表現デザイナ」なる ASP.NET MVC3 アプリケーションを、モデルとコントローラ部分を F# で作成した。そして作成した ASP.NET アプリをインターネットに公開するにあたり、ホスティング先として Windows Azure を選んだ(URLは下記)。 http://regexdesignfs.cloudapp.net/ 以下、その顛末を記す。 なぜ Windows Azure?実は自分、別途 ExpressWeb のホスティングサービスも契約している。ExpressWeb http://www.epw.jp/ こちら、月額相当 \263 なのに、ASP.NET MVC3 のアプリも当然載せられる上、SQL Server も使えて、サブドメインも立て放題という、ものすごい太っ腹なホスティングサービスだ。 しかも 14日間無料というお試しプランまであるという。 参照 http://www.epw.jp/tabid/376/Default.aspx にも関わらず、Azure を選んだのは、 とりあえず今回は無料 で使えるから。 出典は下記。 フリーミアム万歳!Azure無料化で誰でもタダでWindowsServerをクラウドに持てる時代がやってきた http://blogs.itmedia.co.jp/isago/2011/02/azurewindowsser-ca07.html 上記記事にあるとおり、Windows Azure Platform 特別導入プランを契約すると、無償利用枠が付いてくるのだが、この無償枠が XSインスタンスの750時間/月分 だというのだ。 1日は24時間なので、1ヶ月は 24 x 31 = 744時間。 すなわち、1ヶ月あたり 750 時間までの無償枠だということは、ずーっと動かし続けていてもタダなのである。 ということで、ちょっと Windows Azure でやってみよう、と思い立った次第。 もちろん、XS (eXtra Small ) インスタンスなので、CPUパワーが非力であることもさることながら、I/O 性能も制限されているようなので、本格運用には少々つらいかもしれない点は承知しておくべし。 それにあくまでも XS インスタンス x 1つぶんの1ヶ月相当時間が無償枠なだけなので、いくつもの Web アプリをどかどか無料で立てられるわけではない。 また、SQL Azure まで無料になるわけではないので、なんらかの RDBMS と併用したい場合も注意が必要である。 今回の ASP.NET アプリは、「正規表現デザイナ」ということで、一切のストレージを使わないことから、お気楽に Windows Azure の無償枠を使うことができた。 はじめから Windows Azure プロジェクトで作りはじめる必要はないさて、"無料だから" というわけで Windows Azure を使うことにしたのだが、実ははじめから Azure 上での公開を考えて作り始めたわけではなかった。はじめは、Visual Studio 2010 Pro を使って、ごく普通に ASP.NET MVC3 アプリを作り始めたのである。 ほぼ完成形になってから、ふと、「そうだ、Azure 上に立ててみよう」と思い立ったのである。 しかし心配は要らない。 一般的な ASP.NET アプリを Azure 上で稼働させるようプロジェクトを作り直すのは、ほとんど手間いらずである。 自分は次の手順でやってみた。 ※そうそう、Web Platform Installer を使って、予め Windows Azure Tools for Microsoft Visual Studio 2010 およびその言語パックをインストールしておくこと。 Step1. Windows Azure プロジェクトの新規作成 まず Visual Studio にて新規プロジェクトの作成を始める。 「新しいプロジェクト」ダイアログにて、.NET Framework = 4.0、カテゴリ = Visual C# > Cloud、Windows Azure プロジェクトのテンプレートを選んで OK する。 ![]() このとき、続けて、どんなロールをこのプロジェクトに新規追加するか尋ねられるのだが(下図)、ここで何も選択・追加せずに黙って「OK」を押すのがポイント。 ![]() Step2. 既存プロジェクトのソリューションへの追加 次に、先に作り込んでおいた ASP.NET アプリケーションを、こうして新規作成した Windows Azure プロジェクトのソリューションに追加する。 ![]() 今回の ASP.NET アプリは、F# によるクラスライブラリとして書かれたモデル + コントローラ部分と、C# によるビューの、2つのプロジェクトに別れているので、各々ソリューションに追加することになる。 ![]() Step3. 既存プロジェクトのロールへの追加 ソリューションへの追加が完了したら、ここで、Windows Azure プロジェクト以下にある、「ロール」と書かれたフォルダを右クリックして、「ソリューション内の Web ロールプロジェクト...」を選択する。 ![]() ここで、先ほどソリューションに継ぎ足した ASP.NET Web アプリプロジェクトが選択肢に出てくるので、これを選んで OK をクリックして完了。 ![]() あとはビルドして、Windows Azure プロジェクトを右クリックしての「パッケージ...」なりなんなりして、Windows Azure にデプロイすればよい。 あっけないが、これだけである。 ちょっとつまずいたこと実は最初、Windows Azure にデプロイしてからその URL を開いて見たところ、サーバー側で必要なアセンブリがロードできないという例外が発生して動作しなかった。確認したところ、ロードできなかったアセンブリは FSharp.Core であるとのこと。 そこで、ソリューションエクスプローラから、プロジェクトの「参照設定」ツリーを開いて、FSharp.Core のプロパティを開き、 「ローカルコピー」を「True」 に設定しなおして再パッケージ、デプロイしなおしたところ、無事解決、正常動作するようになった。 ![]() まとめ以上、いかがだろうか。手持ちの ASP.NET Web アプリを Windows Azure 上で公開するよう、プロジェクトを再構成するのは、格段難しいわけではないようだ。 もっとも、今回は、SQL Azure や Storage を使わない Web アプリだったので、それら周辺との接続が不要だったため、容易だった面もたしかにあるが...。 また、いろいろと制約はあるものの、無償枠があるのでこれを上手く活用して Windows Azure への第一歩を踏み出すのも悪くないと思った次第。 2011年 12月 14日
この記事は F# Advent Calendar 2011 の14回目です。
←前回 @smallgeek さん「F# 3.0 の Query expressions」 →次回 @teramonagi さん はじめに昨年も参加させて頂いた F# Advent Calendar。あれから1年も経ったのに、 F# のスキルはパイプライン演算子と部分適用しか進歩していない自分に愕然 とする今日この頃である。 さておき。 今回のお題は「正規表現デザイナを ASP.NET MVC3 + F# で作ろう!」である。 正規表現デザイナとはここでいう "正規表現デザイナ" とは、何のことはない、正規表現パターンと検索対象文字列とをフォーム上から入力して「実行」すると、その正規表現パターンに該当した箇所を、色分けして表示するという、ただそれだけの ASP.NET MVC3 Web アプリである。具体例を示そう。 正規表現パターンに "\d+"、 検索対象文字列に "My ID is 001, Your ID is 002." と入力して実行すると、 "My ID is <span class='Even'>001</span>, Your ID is <span class='Odd'>002</span>." という HTML が返るような、Web アプリを作るわけである。 正規表現パターンには何ヶ所かがマッチしうるので、偶数番目・奇数番目にマッチした順で色分けする。 そのために、マッチした箇所を Even ないしは Odd の CSS クラス名を付けた span 要素でくくる。 こんな Web アプリを、コードは F# で書いて実装してみよう、というわけだ。 実は 3年ほど前に Haskell で同じネタを本ブログに載せていたのだ(下記)。 http://devadjust.exblog.jp/7963308/ これと同じお題目を、では F# で書いたらどうなるか、という趣旨である。 なお、上記投稿は Haskell の練習だったので、実際の Web アプリには仕立てるまではしなかった。 ようするに、Haskell で Web アプリを書く知識がなかったのである。 しかし、今回はなんといっても F# である。 F# は .NET Framework 上の言語ファミリの一員でもあるので、ASP.NET アプリとして完成させるのは容易なのである。 ということで、解法・アルゴリズムは、上記 Haskell での解き方を踏襲してみた。 入力まずはこんな感じで。let input = "My ID is 001, your ID is 002." 正規表現パターンマッチなんの芸もなく、素直に .NET Framework 標準の Regex クラスを使って、検索対象文字列に対する正規表現パターンのマッチングを行う。マッチ結果は MacthCollection 型で返る。 これをこのあと、シーケンス処理でどんどん加工していくために、LINQ の Cast<T> 拡張メソッドを適用し、型のわからない IEnumerable から IEnumerable<Match> へ射影しておく。 open System.Linq マッチ種別ごとの分割点を求めるまず、入力 input を、マッチしていない・奇数番目にマッチした・偶数番目にマッチした、という箇所ごとに分割する。ということで、分割位置とマッチ種別(マッチしていない/奇数番目にマッチした/偶数番目にマッチした)のタプルを求めてみよう。 早速、マッチ種別を表現する列挙型を定義しておく。 type MatchType =すべてが F# だけで完結するのであれば判別共用体のほうがいいのだと思う。 しかし、このあと ASP.NET Web アプリに仕立てるにあたって不都合があったので、あえて相互運用に長けた列挙型で定義する。 次に、Regex.Matches の結果得られた Match オブジェクトの集合に対して、マッチした順に偶数番目・奇数番目の印を付けなくてはならない。 そこで Match のコレクションと、Even, Odd, Even... という無限シーケンスとを zip する。 こうすることで、各マッチ箇所(Match オブジェクト)に Even か Odd かの情報をタプルとして抱き合わせることができるようになる。 では、Even, Odd, Even, Odd... を延々と返す無限リストを定義しよう。 F# では組み込みの Seq.initInfinite を使うことで無限シーケンスを生成することができる。 こんな感じ。 let oddEven = Seq.initInfinite (fun n -> if n % 2 = 0これで oddEven は偶数・奇数を表す列挙型値の無限シーケンスとなった。 では zip する。 Regex.Matches(input, pattern).Cast<Match>()さて、分割位置だが、Match オブジェクトの Index および Length オブジェクトから導くことができる。 今回の例では、 { Match {Index=9, Length=3}, Match {Index = 25, Length=3}} なので、 My ID is |9文字目|001|9文字目+3文字|, Your ID is |25文字目|002|25文字目+3文字|. というように、Index と、Index + Length を並べていくことで分割できる。 これに、先程 zip で付加したマッチ種別を合わせて、 My ID is |9,以後奇数番目マッチ|001|12,以降非マッチ|, Your ID is |25,以後偶数番目マッチ|002|28,以後非マッチ|. すなわち、 [(9,Odd), (12,None), (25,Even), (28,None)] というタプルの集合を求めるといいわけだ。 ということで、Seq.map を使って、(Match, MatchType) のタプルを、(Index, MatchType) と (Index + Length, MatchType) の2つのタプルの集合に射影する。 Regex.Matches(input, pattern).Cast<Match>()しかし、このままでは、"集合の集合" となってしまい、平坦に処理できない。 そこで、Seq.concat を使って、1重のシーケンスに平す。 すなわち、LINQ でいうところの SelectMany だ。 Regex.Matches(input, pattern).Cast<Match>()以上で求まった分割位置を let points = ... として変数 points に束縛しておく。 分割位置から断片へこうして分割位置が求まったので、あとはこの分割位置ごとに文字列 input を断片にばらしていく。まず、分割位置の集合 points には、行頭と行末の位置が含まれていない。 そこで、これを継ぎ足した集合を用意する。 let seq1 = Seq.append (seq [|(0, MatchType.None)|]) points頭に行頭位置を継ぎ足した集合と、末尾に行末位置を継ぎ足した集合の、ひとつずれた集合2つの組み合わせを用意するのがミソ。 この2つの集合 seq1 と seq2 を zip してやれば、 [((0, None), (9, Odd)), ((9, Odd), (12, None)), ...] というように 0~9、9~12、... という文字列の該当範囲を表現するタプルの集合が手に入るのだ。 とはいえ、ネストしたタプルののままでは、このあとの取り扱いがややこしい。 Seq.map を使って、先に、この ((開始位置, 以後のマッチ種別), (終了位置, 以後のマッチ種別)) というタプルのタプルを、 (開始位置, 文字数, この範囲のマッチ種別) のタプルに射影して整理しておこう。 Seq.zip seq1 seq2ここまでできたら、もう完成である。 (開始位置, 文字数, この範囲のマッチ種別) のタプルの集合を、入力文字列 input に対する (該当範囲の部分文字列, この範囲のマッチ種別) の集合へ射影してやればよい。 ただし、タプルへの射影だと、このあと ASP.NET Web Page ( .cshtml ) で結果を描画するときに少々面倒である。 そこで、先に「該当範囲の部分文字列」と「この範囲のマッチ種別」の2つのプロパティを持つ .NET クラスを定義しておこう。 クラスの名前は、入力文字列 input を正規表現パターンのマッチごとにばらした "断片" なので Fragment としておく。 type Fragment(matchType:MatchType, content:string) =これで、Fragment オブジェクトの集合として、結果が取得できる。 Seq.zip seq1 seq2 結果のレンダリング以上で、IEnumerable<Fragment> が手に入るので、これを ASP.NET Web Page にて描画すればよい。イメージとしてはこんな感じ。 @model IEnumerable<Fragment> 成果以上、F# 部分のコードをまとめて再掲する。open System.Linq ideone.com にも掲載しておいた。 http://ideone.com/RdnWl 作成した ASP.NET Web アプリは、Windows Azure 上に配置してみた。 どうということはないアプリであるが、URL は下記のとおり。 http://regexdesignfs.cloudapp.net/ プロジェクト一式はとりあえず SkyDrive に配置しておく。 http://bit.ly/rKkvCg この程度のコードでライセンス云々言うのもはばかられるが、Ms-PL か CPL かなにか、とにかく自由に使って頂けることでまったく差し支えない。 まとめ以上、いかがだったろうか。正直、あまり "F#らしさ" が活かせていないような感じではある。 ひたすら、zip と射影を繰り返すだけなので、C#/VB で LINQ で書いても大体同じようになるだろう。 F# の良さを活かすには、解法・アルゴリズム次第という面もあるので、これを機会に「こうして解いたら、こう書けるよ」などコメントやツイート頂戴できれば幸いである。 とはいえ、あくまでも記号的な話になるのだけれども、F# ではタプルを容易に書けることや(だって、カッコでくくってカンマ区切りで列記するだけ)、{ ~ } の記述がないことから、シンプルに記述出来る点は相変わらず魅力である(Fragment クラスの記述を見よ)。 あと、C#/VB であっても、LINQ で書いていると「変数に代入」するという場面が激減すると思う。 今回の F# のコードも同様で、Fragment クラスはプロパティを書き換えできない "不変オブジェクト" として実装してある。 かように、「代入? ナニソレ?」的な指向・思考でも、何ら苦にならずにプログラムを開発できる自信がついてきた。 初めて Haskell 勉強したときは 「いちど変数を初期化したら、以後、変更できないだって!? そんなんでプログラム書けるのか!?」 などとすごいカルチャーショックを受けてたくせに、である。 あと、ASP.NET アプリも F# でほとんどの部分を記述できる、というのも関数型言語の一族の中では毛色の変わったところだと思う(.cshtml 内のマークアップだけは C#/VB で記述することになる)。 「F# で Web アプリを書くとなにがおいしいの?」という質問に対しては、今回のネタのように、"計算" が多いアプリについては、F# でかくとすっきり明確に記述できる利点はある。 例えば、Wiki 記法を HTML に展開する、そういう CMS などを構築するときは F# だといいかもしれない。 長々と書き連ねた。 以上で F# Advent Calendar 2011 の14回目は完了! 2011年 12月 03日
はじめに自分は各種ITインフラストラクチャやサーバーの設営管理も多少手がけてはいるが、ホームベースはあくまでも C# による ASP.NET Web アプリケーション開発である。開発環境は Visual Studio。 正直に言って、 かなり重度のインテリセンス中毒 である。 なので、たとえ IT インフラも手がけているとは言え、インテリセンスが無い PowerShell 環境では、なかなか学習曲線が上がらず、ついつい敬遠しがちである。 PowerShell 使ってもどうせ COM とか WMI 呼んじゃうんでしょ、だったら F# スクリプトのほうが、インテリセンスも構文カラー強調もリアルタイムエラー報告も Visual Studio で用意されてていいよね! などと、PowerShell ファンには大変申し訳ないことを吹聴していたりする。 そんな私が、なんと、 PowerShell Advent Calendar 2011 にエントリ したのだ!? Advent Calendar とは?Advent Calendar とは、12/1 からクリスマスである 12/25 までをカウントダウンしていくカレンダーなのだそうな。で、ここでいう "Advent Calendar" とは 各種 IT コミュニティやら何やらの集まりが、これになぞらえて、技術系 Advent Calendar と称して、12/1 から 25 に至るまで、リレー形式でなにかしらの技術テーマに沿ってブログ記事など投稿していくという "イベント" のことである。 去年の記事になるが、gihyo.jp の記事など参考まで。 本日12月1日より,プログラマ有志による技術系Advent Calendarが各所ではじまる http://gihyo.jp/news/info/2010/12/0102 "PowerShell Advent Calendar" とはその名のとおり、PowerShell をテーマにして、クリスマスまで、リレー形式でブログ記事など投稿しよう!というものだ。 現在も ATND で参加者募っているようなので(下記URL)、是非参加されたし。 PowerShell Advent Calendar 2011 http://atnd.org/events/22073 PowerShell ASPさていよいよ本題。あれだけ PowerShell を敬遠している自分。 しかし実はを言うと、前々からひとつ気になってしようが無いプロダクトがあるのだ。 その名も PowerShell ASP。 ここでいう "ASP" は Active Server Page の略、 "ASP.NET" の頭の ASP と同じ意味ですよ。 すなわち。 HTML の文中に、PowerShell のコードを記述する(!)ことで、動的 Web ページを作成できる、というのだ。 昔懐かしの ASP のような JScript や VBScript ではない。 現代の ASP.NET でのトレンドな C# や VB でもない。 PowerShell ですよ、PowerShell。 PowerShell で Web アプリを書くってどういうことですか一体。 ということで、実際に試してみた。 ダウンロードとインストール下記の InfoQ の記事を参考にするなど。InfoQ - Windows PowerShellを使用したASP.NET プログラミング http://www.infoq.com/jp/news/2008/07/PowerShellASP リンク先をたどると、PowerShell ASP の V3 がリリースされているというので、さらにそのリンク先をたどる。 下記ページにたどり着くので、同時接続数は1つに限定されるものの無償利用可能な Personal Edition をダウンロード。 http://www.powershellinside.com/powershell/asp/download.aspx インストーラの .exe ファイルがダウンロードされるので早速実行。 セットアップのウィザードに従って進めていく。 途中、IIS への設定らしき設問があるが、今回はお試しということでチェックを外して先へ進む。 難しいことはなく、普通にインストールは完了。 Web アプリの新規プロジェクト構築Visual Studio の利用は必須ではないが、とりあえず手慣れた環境なので、Visual Studio 上で進めてみる。なお、無償版である Visual Web Developer Express でもほぼ同様の手順で再現できるはず。 話が逸れたが、さて、早速まずは Visual Studio を起動。 新規プロジェクトの作成を実行し、.NET Framework のバージョンは 4、プロジェクトテンプレートから「ASP.NET 空の Web アプリケーション」を選択。 なお、言語は C# でも VB でもどちらでも関係ない(なんてったって、これから PowerShell で書くのだから)。 参照設定に PowerShellASP を追加新規プロジェクトが作成されたら、次は PowerShell ASP のランタイムを参照設定に追加して、この Web アプリプロジェクトに読み込むようにする。64bit 環境であれば C:\Program Files (x86)\PowerShellInside\PowerShell ASP V3\bin フォルダに「PowerShellASP.dll」が配置されているので、これを参照設定に追加する。 web.config の構成 - .ps1x ファイルの関連付設定次に web.config を書き換える。下記のとおり、httpHandlers セクションを追加し、拡張子 .ps1x への GET または POST 要求が発生したら、PwerShwllASP.dll に収録されている、PowerShellASP 名前空間の PSHandler クラスに、その要求の処理を任せるように設定。 <configuration> <system.web> <compilation debug="true" targetFramework="4.0" /> <httpHandlers> <add path="*.ps1x" verb="GET,POST" type="PowerShellASP.PSHandler,PowerShellASP"/> </httpHandlers> </system.web> </configuration> 以上で環境設定は完了。 いよいよページを記述それでは、いよいよ PowerShell で Web アプリのページを記述していくのだ。新規アイテムの追加で、とりあえず HTML ページを追加する。 追加したら、ソリューションエクスプローラにて、この新規追加した HTML ファイルの名前を、"index.ps1x" に変更する。 続けて、次のように PowerShell のコードを書き足す。 ... </head> <body> <% ls c:\ | %{ %> <div><% $_ %></div> <% } %> </body> </html> パイプですよパイプ! それに "ls" とか! (※Microsoft 系のコマンドプロンプトのみご存じな方に説明すると、いわば dir に相当) よもや、HTML ページテンプレート内にパイプを記述する日が来るとは思ってもみなかった。 で、Ctrl + F5 などで実行。 残念ながら拡張子 .ps1x が動的 Web ページであることが Visual Studio はわかっていないので、まずは開発サーバーによるディレクトリ一覧が表示されてしまうが、ここで今作った index.ps1x をクリックすると... ![]() おお! 我が PC の Cドライブルートフォルダが丸見え! さすがサーバー管理系に強い PowerShell である。 同等の出力を行う C# による ASP.NET Web Page ( .cshtml ) を記述してコード量を比べようと思ったが、そもそもフォルダもファイルもひとつの一覧として抜き出したり、ファイル属性を "d-r--" 形式に書式化したり、それらファイルやフォルダごとの情報を連結したり... といったことを考えるだけで萎えてしまった。 開発元の公式ホームページにはほかにも、現在その OS で実行中のプロセス一覧をページ上に表示するなど、"このサーバーを攻撃してくれ" といわんばかりの、PowerShell ならではの危険な香りがそこはかとなくするサンプルも掲載されている。 以上、なかなかに愉快な、PowerShell ASP デビューの記録である。 2011年 11月 29日
ASP.NET MVC3 による Web アプリ開発での話。
カスタム入力検証のクライアント側実装@shibayan の下記ブログ記事を参考に、モデルに自作のカスタム検証属性を付与し、さらにクライアント側スクリプトでもそのカスタム検証を行う実装を書いた。ASP.NET MVC 3 で独自の検証属性を作成して、クライアントサイド検証を行う http://d.hatena.ne.jp/shiba-yan/20110108/1294423577 ASP.NET MVC2 用にカスタム検証属性とそのクライアント側実装はなんどか書いたことがあったが、ASP.NET MVC3 用は初めて。 上記ブログ記事のお陰で、無事実装することができた... ...と言いたかったところだが、自分のはやとちりで、うまくいかずはまってしまった。 クライアント側実装が動作しない!?ASP.NET MVC3 の独自入力検証のクライアント側実装では、下記のような JavaScript コードを記述して、カスタム検証ロジックを実装する。// 検証ロジックの記述 jQuery.validator.addMethod("myValidate", function (value, element, param) { // ここで検証結果: true か false かを返す }; // "控えめJavaScript" のパース処理で認識してもらえるよう、名前で登録 jQuery.validator.unobtrusive.adapters.addBool("myValidate"); さてここで私は、上記コードを、$(function(){ ... }) 内、すなわち document ready のタイミングで実行するように書いてしまったのだ。 そうすると何がおきるか。 何も起きないのである。 せっかく書いたクライアント側のカスタム検証スクリプトが一切呼び出されないのである。 ※ちなみに、サーバー側実装は申し分なく期待どおりに正常動作した。@shibayan に多謝。 正解は...いろいろ試行錯誤してようやくたどり着いた正解は、上記コードを、document ready のタイミングではなく、上記コードを記述した .js ファイル内にインラインで書く こと。 つまり、その .js ファイルがロードされたら実行されるようにしておくのだ。 というのも、ASP.NET MVC3 の "控えめ JavaScript" ベースのクライアント側検証エンジンは、document ready のタイミングで、 jQuery.validator.unobtrusive.parse() を実行するからだ。 jQuery.validator.unobtrusive.parse メソッドでは、HTML DOM を走査して、data-val-ほげほげ といった "控えめ JavaScript" 方式のためのマークアップを探しだし、適切にイベントハンドラを配線して、検証コードと紐づけていく。 すなわち、 jQuery.validator.unobtrusive.parse() の実行後にカスタム検証ロジックを登録しても、すでに手遅れ、検証のためのイベントハンドラの配線は行われないのである。 ...というつまらぬところではまってしまった。 わかってしまえば、至極当然、当たり前のことなのであるが。 以上、恥ずかしい失敗ではあるが、覚え書きということで。 2011年 10月 19日
IT コミュニティ CLR/H の第63回勉強会では、マイクロソフト・荒井省三さんによるセッションにて、DLR ( Dynamic Language Runtime: 動的言語実行環境 ) にまつわるお話しを頂いた。
そのおさらいと成果を報告。 マクロ機能Microsoft Office 製品には、"VBA" ( Visual Basic for Application ) というプログラミング言語が搭載されており、このプログラミング環境を用いることで、Word や Excel などに機能追加したりすることができる。このように、何らかの簡易なプログラミング言語を内蔵して、そのアプリ自身に機能追加することを容易にする仕組みは、少なからず見かける。 ここではそのような機能のことをマクロ機能と呼ぶことにする。 そこで、CLR/H 第63回勉強会での成果を活かして、自作する .NET アプリにマクロ機能を搭載するチュートリアルに臨んでみた。 お題メモ帳のような WPF アプリ = Notepad1 を作成、この Notepad1 を IronRuby で書いたスクリプトコードによって機能追加できるようにする。事前準備今回はマクロ機能の言語として Ruby を選んだので、まずは Ruby の .NET DLR 実装である IronRuby をダウンロード、インストールしておく。IronRuby http://ironruby.codeplex.com/ アプリ本体の開発下図のような WPF アプリ、Notepad1.exe を作成しておく。![]() あと、このあとのマクロ機能の実装で、言語として IronRuby を使うので、先程インストールした IronRuby のフォルダ ( C:\Program Files (x86)\IronRuby 1.0v4\bin ) から、下記アセンブリ ( .dll ) を参照設定に追加しておく。
マクロ機能の仕様下図のようなフォルダ構造とする。![]() この Macros サブフォルダ内に配置しておいた Ruby スクリプト ( .rb ) を実行時に読み込んで、Notepad1.exe の [マクロ(M)] メニューから呼び出すようにする。 Macros サブフォルダ内の .rb ファイルのファイル名がそのまま Notepad1.exe の [マクロ(M)] メニューのメニューアイテムとして表示される寸法だ。 ![]() 構成ファイルの設定アプリ内から IronRuby スクリプトを実行する準備として、今回は構成ファイルにいくつか設定を施しておくことにする。下記のとおり、microsoft.scripting 構成セクションを認識できるよう、構成セクションハンドラを仕込んでおく。 その上で、microsoft.scripting 構成セクションに、このアプリに搭載されるスクリプト言語やそのスクリプトファイルの拡張子などを設定しておく。 <configuration> <configSections> <section name="microsoft.scripting" requirePermission="false" type="Microsoft.Scripting.Hosting.Configuration.Section, Microsoft.Scripting"/> </configSections> <microsoft.scripting> <languages> <language extensions=".rb" displayName="IronRuby" type="IronRuby.Runtime.RubyContext, IronRuby" names="IronRuby;Ruby;rb"/> </languages> </microsoft.scripting> ... [マクロ(M)] メニューの実装[マクロ(M)] メニューアイテムに予めダミーのサブメニューアイテムを追加しておく。すると、[マクロ(M)] メニューが開かれるときに SubmenuOpened イベントが発生するのでこれをハンドル。 SubmenuOpened のタイミングで Macros フォルダ内のスクリプトファイルを列挙し、ファイル名のメニューアイテムを追加していく。 このメニューアイテムに、"MacroCommand" という自作のコマンドを関連付けし、コマンドのパラメータとしてスクリプトファイルのフルパスを格納しておく。 "MacroCommand" の実装...と、まぁ、ここまでは下準備。以上の実装により、[マクロ(M)] メニュー以下、スクリプトファイル名のメニュー項目が選択されたら、”MacroCommand" という自家製のコマンドが、スクリプトファイルのフルパスを引数に伴って発火することになる。 "MacroCommand" の実行を Macro_Executed メソッドにバインドして、この Macro_Executed メソッド内で、引数としてやってきたスクリプトファイルのフルパスからスクリプトコードを読み込んで実行すればよい。 まずはスクリプトファイルのフルパスを取得。 public void Macro_Executed( スクリプトランタイムの生成次に、スクリプトコードの実行基盤となるスクリプトランタイム ( Microsoft.Scripting.Hosting. ScriptRuntime型 ) のオブジェクトインスタンスを生成する。スクリプトランタイムオブジェクトの生成には、普通に new するのをはじめ、いくつかやり方がある。 今回は .config 構成ファイルの設定に沿ってスクリプトランタイムオブジェクトを生成する、CreateFromConfiguration 静的メソッドを使った。 var scriptRuntime = ScriptRuntime.CreateFromConfiguration(); 言語エンジンの生成スクリプトランタイムを生成したら、スクリプトランタイムに言語エンジンを生成してもらう。これまたいくつかやり方が用意されているが、今回は、スクリプトファイルの拡張子から、適切な言語エンジンを生成する、GetEngineByFileExtension メソッドを呼び出すことにした。 var ext = Path.GetExtension(macroPath); スコープ言語エンジンが入手できたら、もう、スクリプトコードをその言語エンジンに与えて実行することができる。しかしそれだけでは、この Notepad1.exe 自身とはなんの関係もない、独立したプログラムコードが動くだけに過ぎない。 この Notepad1.exe 自身の内部を、これから実行するスクリプトコードでいじれるようにしてやらねば、マクロ機能としては成り立たない。 そこで、"スコープ" という仕組みを使う。 スコープと呼ばれる、ある種の辞書オブジェクトを介して、アプリ側からスクリプトコードへ、名前を付けてオブジェクトを開示するのだ。 まずは "スコープ" オブジェクトを生成する必要がある。 これまたスクリプトランタイムに生成してもらう。 var scope = scriptRuntime.CreateScope(); スコープオブジェクトが手に入ったら、スコープの SetVariable メソッドで、アプリ内のオブジェクトモデルを名前を付けて登録する。 そう、Web ブラウザが HTML DOM オブジェクトモデルを、JavaScript エンジンに引き渡すように。 今回はチュートリアルなので凝ったことはせず、単純に Notepad1.exe に貼り付けた TextBox オブジェクトをそのままスクリプトコードに開示することにした。 scope.SetVariable("textBox", this.textBox1);これで、スクリプトコード内から "textBox" という名前で、Notepad1.exe に貼り付けた TextBox オブジェクトを操作する準備ができた。 実行ここまでできたら、ようやく、こうして作成したスコープと、実行するスクリプトファイルの二つを引数に言語エンジンに渡して、スクリプトの実行となる。engine.ExecuteFile(macroPath, scope); スクリプトの例例えば、次の Ruby スクリプトを記述した "To upper case.rb" ファイルを Macros サブフォルダに置いておくと、Notepad1.exe のテキストボックス内に記述した英字がすべて大文字に変換されるマクロ機能を追加できる(メニュー [マクロ(M)]-[To upper case] を選ぶと実行される)。textBox.set_Text textBox.get_Text.upcaseスコープで開示した WPF の TextBox オブジェクトに、"textBox" という名前でアクセスできているのがわかる。 ※IronRuby なので、プロパティへのアクセスには set_プロパティ名/get_プロパティ名のアクセッサメソッド直接呼び出しが必要らしい。要確認。 プロジェクト一式以上、ソースコード一式を SkyDrive にアップロードしておいた。DLR Scripting Tutorial - Notepad1.zip http://bit.ly/poJdX2 IronPython についてすでにお気づきかも知れないが、この Notepad1.exe、IronPython をインストールすれば、Python スクリプトによってマクロ機能を書くこともできる。.config ファイルの languages セクションに IronPython についてのエントリを書き加え、Macros フォルダに拡張子 .py で Python スクリプトを置けば OK だ。 まとめこのように、自作アプリに軽量言語によるマクロ機能を追加するのは、容易に行えることがわかった。今回はチュートリアルということで、WPF の TextBox オブジェクトを直接スクリプトに開示するのみであったが、ちゃんとしたオブジェクトモデルをデザインしてスクリプトに開示することで、そのアプリケーション全体を自由にコントロールさせることができるようになる。 2011年 10月 17日
.NET アプリ全般的な話。
トレース機能とトレースリスナ.NET Framework には Trace クラスや TraceSource クラスなどによるトレース機能(ある種のロギング機能といっていいだろう)が備わっている。アプリ本体側から Trace.Write とかすると、そのアプリケーションに設定されている "トレースリスナ" オブジェクトに引き渡され、各トレースリスナオブジェクトが然るべきところに書き込みを行う、という寸法だ。 たとえば、Windows OS のイベントログに書き込むというトレースリスナが .NET Framework には標準装備されている。 これをアプリにセットアップしておくと、アプリからのトレース出力が、Windows のイベントログに書き込まれるようになる。 アプリへのトレースリスナの組み込みは、コード上から明示的に行えるほか、App.config や Web.config などアプリケーション構成ファイルにて指定することができる。 トレースリスナは自作できる当然のことながら、トレースリスナは自作できる。TraceListener クラスから派生した自作クラスを用意し、Write メソッド、WriteLine メソッドを override して実装するだけ。 とは override した Write/WriteLine メソッド内で、好きなようにトレース出力を扱えばよい。 こんな風に、MongoDB に書き込む事例もある。 無聊を託つ - TraceListner into MongoDB http://takepara.blogspot.com/2011/10/tracelistner-into-mongodb.html 自作トレースリスナにパラメータ指定するには?さて、トレースリスナを自作する場合、独自のパラメータ指定ができたほうが便利なことも多いだろう。たとえばトレース出力を片っ端からメール送信するトレースリスナを自作する場合、宛先や件名などを App.config のトレースリスナ設定行に記述しておきたいのではないだろうか。 もちろん、appSettings 構成セクションを使えばお気楽である。 ただ、トレースリスナ設定行とセクションが違うので、設定箇所が離れてしまうのが難点か。 appSettings 構成セクションがどんどん "汚染" されるのも、ちょっといただけない。 ということで実は、.NET Framework はそんな要望にすでに応えており、トレースリスナ設定行に独自パラメータを併記できるようになっていた。 まずアプリケーション構成ファイルのトレースリスナ設定行には、次の要領で独自パラメータを XML 属性として記述しておく。 <system.diagnostics> <trace> <listeners> <add name="MyListener" type="MyListenerClass, MyAssembly" to="foo@bar.com" sibject="wow!"/> </listeners> </trace> </system.diagnostics> 自作トレースリスナで GetSupportedAttributes メソッドをオーバーライドする。 ここで、独自パラメータ名を返すようにするのだ。 protected override string[] GetSupportedAttributes() { var attrs = new List attr.Add("to"); attr.Add("subject"); return attrs.ToArray(); } こうしておくと、自作トレースリスナのコード上で、基底クラス TraceListener の Attributes プロパティを参照したときに、独自パラメータを参照できる。 public override void WriteLine(string message) { var to = this.Attributes["to"]; var subject = this.Attributes["subject"]; ... } 以上、ご参考まで。 2011年 10月 17日
先日10/15(土)に開催された、CLR/H 第63回勉強会のライトニングトークに、このたびも登壇させて頂いた。
そのときの資料を下記のとおり slidshare に公開。 View more presentations from Jun-ichi Sakamoto ただし、slideshare ではせっかくのアニメーションが見られない。 そこで、SkyDrive にもアップロードして公開。 http://t.co/Dsxam6Yw Silverlight が必要だが、きちんとアニメーションも動作するので、わかりやすいと思われる。 ちなみに本件で大変参考になったブログ記事はこちら。 torutkの日記 2010-05-29 .NETのメモリ管理と断片化問題 http://d.hatena.ne.jp/torutk/20100529/p1 大変よくまとまっていて、わかりやすい。 2011年 09月 29日
Web アプリケーションの話題。
自分はもっぱら、ASP.NET による Web アプリケーションを書くのが主な仕事になるのだが、さて。 If-modified-since 要求ヘッダにちゃんと反応させるとある事情があって、半固定的なコンテンツをレスポンスに返す HTTP ハンドラを自前で書くことになった。で、ブラウザのキャッシュを有効活用してもらうよう、If-modified-since 要求ヘッダ値に書かれた日時情報をちゃんと見るように実装。 すなわち、ブラウザがキャッシュに覚えているコンテンツのタイムスタンプがじゅうぶん新しければ、HTTP 304 Not Modified だけを返すようにしていた。 "じゅうぶん新しいかどうか" の日時計算にあたっては、If-modified-since 要求ヘッダ値を DateTime.Parse() に読ませて、.NET Framework の DateTime 型に変換して比較・計算する実装としていた。 さて、通常、If-modified-since 要求ヘッダ値には次のような文字列が格納されているはずである。 Wed, 28 Sep 2011 14:42:36 GMT .NET の DateTime 型は、Parse 静的メソッドによってこの文字列を正しく DateTime 型の値に解析して返してくれるわけだ。 解析できない日付文字列が!ところが、実際に試してみたところ、どういうわけか、この DateTime.Parse を呼び出しているところで下記の例外が発生してしまう現象に遭遇。FormatException - 文字列は有効な DateTime として認識されませんでした。インデックス 0 から始まる位置に不明な単語があります。 いったいどんな If-modified-since 要求ヘッダ値がきたのか、確認してみると、次のとおり。 Mi, 28 Sep 2011 14:42:36 GMT ん? 曜日の文字列のところが "Wed" ( 水曜日:Wednesday ) ではなく、"Mi" になっている。 "Mi" っていったいなんだ? "Mi" はドイツ語での水曜日の略称表記ネットで検索してみたところ、これはドイツ語における曜日名の略称表記らしい(ドイツ語に限らないかもしれないが)。英語表記なら、"Sun","Mon","Tue","Wed","Thu","Fri","Sat" となるが、これがドイツ語だと "So","Mo","Di","Mi","Do","Fr","Sa" となるそうな。 ちなみに、月の略称表記も英語とドイツ語とで異なるのだが、9月に関してはたまたま、両者とも "Sep" で同じであった。 RFC 読んでないので、このような非英語圏の表記で if-modified-since 要求ヘッダを送ってもよいことになっているのかどうかは知らない。 とにかく現実に、このような if-modified-since 要求ヘッダ値を送ってよこすユーザーエージェントが実在するということだ(非常に希ではあったのだが)。 なお、対策としては、DateTime.Parse についてどの言語のカレンダに基づいて解析するか、カルチャ指定のオプションがあるはずなので、それを駆使することも可能かと思われる。 しかし、そもそもどのカルチャで解析すべきかの判断・判定処理が事前に必要になる。 希なケースであるし、そこまでこだわる必要がなかったので、単純に DateTime.TryPase して、解析できなければ愚直にコンテンツを返すことで決着させた。 2011年 09月 17日
Windows OS に限定される話になるが、さて。
Windows にはウィルス対策ソフトとの橋渡しをする API がある?最近の Windows OS には、インストールされているウィルス対策ソフトを使って、ファイルがコンピュータウィルスでないか・感染していないか、検出(スキャン)するための API が用意されていると聞いた。※"コンピュータウィルス" という用語は、マルウェアやワームなどは含まないのが本来の意味であるのだろうが、本投稿ではそういったもの一切合切まとめて "ウィルス" と書いてしまってある。ご容赦頂きたい。 実際、Internet Explorer はもとより、Firefox も、インターネット上からファイルをダウンロードしてくると、ダウンロードマネージャ画面にて "スキャン中です" のメッセージとプログレスバーが一瞬表示される。 聞くところによれば、Firefox も、この Windows の API を使って、ウィルス検出を行っているとのこと。 その API というのが、IOfficeAntiVirus COM インターフェースなんだそうだ。 そう、COM インターフェースなのである。 なので、Windows OS の API と言ってしまうと不正確。 すなわち、いろいろなベンダーさんがリリースしていらっしゃるウィルス対策ソフトそれ自身が、IOfficeAntiVirus COM インターフェースを公開・実装しているわけである。 その上で、COM のカテゴリマネージャーから列挙・インスタンス生成できるよう、レジストリに登録しておくわけだ。 Microsoft としては橋渡しをする API を設けたのではなく、共通の規格と標準の手続きを設計・公開して、各ベンダーにそれにのってもらったというところだろう。 .NET から使いにくい & WSH からは使えないしかし、上記のように COM として用意されている仕組みであり、.NET 上の言語からはなかなか呼び出しにくい。そもそもある特定の CoClass をインスタンス化すればいいわけではない。 COM のカテゴリマネージャに問い合わせして、列挙してもらう必要がある。 そんな次第なのでタイプライブラリがあるわけでもなく、Visual Studio 上から参照設定とか、tlbimp.exe でインポート、とすることができない。 ツール類の助けを借りることなく、地道に IDL 宣言を C# 言語などに写経する必要があるのだ。 おまけに、.NET 上の言語ならまだしも、VBScript など IDispatch COM インターフェースを利用する、遅延バインディング系の処理系からだともうお手上げである。 IOfficeAntiVirus インターフェースを備える COM コンポーネント ― ウィルス対策ソフト ― が、同じウィルス検出機能を提供する IDispatch インターフェースを備えているとは限らないからだ。 いちおう、ファイルがコンピュータウィルスでないか・感染していないかを、VBScript など WSH 環境から検出するには、Shell API 経由で、ウィルス検出を行う "動詞 (Verb)" を指定して目的のファイルを "実行" する方法もあろう。 いわば、エクスプローラ上でのファイルの右クリックで現れるコンテキストメニューから、「Microsoft Security Essentials でスキャンします」項目を選ぶのと同じ動作だ。 しかしこれでは、呼び出し側にウィルス検出の結果が戻り値としては返らず、また、ユーザーインターフェースの動作が伴うため、バッチ処理には向かないという面がある。 そもそも、インストールされているウィルス対策ソフトの種類が違えば、ウィルス検出を行う "動詞 (Verb)" も異なってくるのではなかろうか。 .NET でラップする!そこで、IOfficeAntiVirus インターフェースに立脚した、ファイルのウィルス検出を行う .NET クラスライブラリを作成することにした。.NET のクラスライブラリであれば、C#、VB、F# などの .NET 系のプログラミング言語からの利用はもちろんのこと、Windows PowerShell からも利用できるようになる。 さらに RegAsm.exe コマンドを使ったレジストリへの登録を済ませれば、VBScript や JScript などの WSH 環境からも利用できるのだ。 正常動作しない!?ということで早速 C# で実装を完了し、Microsoft Security Essentials がインストールされている Win7 Pro (x64) で動作検証してみた。まずは普通のテキストファイルをスキャンしてみる。 ふむ、S_OK ( 正常 ) が返る。よしよし。 次に、実在しないパス名を与えてスキャン実行してみる。 E_FILE_NOT_FOUND が返るはずだが... あれれ? S_OK が返る。 最後に、テスト用のウィルス、eicar.com を用意して、これをスキャンしてみる。 S_FALSE ( 検出した ) が返るはずだが... またしても S_OK が返る...! いったいどうなっているのか!? 釈然としないまま、さらに、ESET NOD32 Anti Virus 4 がインストールされている、 Win7 Pro (x86) でも動作確認してみる。 COM カテゴリマネージャーからは、どうやら NOD32 らしきコンポーネントが正しく列挙されてくる。 しかし、これをインスタンス化して IOfficeAntiVirus インターフェースを要求してみると、なんと "そんなインターフェースは実装していない" とエラーになるのだ。 スキャン以前の問題である。 もうわけがわかりません。 IOfficeAntiVirus インターフェースはもう古い?そこで、冒頭に書いた、Firefox のことを思い出した。自分の実装ではどうにも正常動作しない。 しかし Firefox はちゃんとウィルス検出をやっているではないか、と。 そこで、Firefox のソースコードを調べてみた。 なんと。 Firefox、というか、Mozilla のコードなのだが、ある世代まではたしかに IOfficeAntiVirus インターフェースにもとづくウィルス検出を行うコードになっている。 ところが、とある世代以降は、IOfficeAntiVirus インターフェースはもう使っていないのだ。 代わりに使われ始めたのは、IAttachmentExecute インターフェースを備えた AttachmentServices という CoClass である。 こいつは、インターネット上からダウンロードしてきたファイルなどを、最終的にファイルシステム上に保存したりするときに利用するらしいのだが、その "保存 (Save)" 処理の一環として、ウィルス検出も行ってくれるのだそうだ。 CodePlex で公開ということで、それまでの実装はいったん捨てて、AttachmentService & IAttachmentExecute に基づく実装にいちから書き直して、.NET クラスライブラリとして完成させた。CodePlex で公開してある。 Anti Virus Scanner for .NET (and COM) http://antivirusscanner.codeplex.com/ いちおう、下記環境で eicar.com の検出と削除が行われることは、自分の手元で確認済みである。 ・Win7Pro(x64) 上の Microsoft Security Essentials ・Win7Pro(x86) 上の ESET NOD32 Anti Virus 4 CD や DVD、SD カードや USB フラッシュメモリなどの外部メディアを、大量にスキャンしたいなどの作業の効率化には役立つかもしれない。 2011年 09月 09日
すごくニッチなネタなのだが、せっかくなので投稿しておく。
Microsoft Small Basic 用の拡張ライブラリを実装する際の話題。 Small Basic についておさらいちなみに Small Basic とは、Microsoft から提供されている、無償利用可能なプログラミング言語およびその開発環境である。Microsoft Small Basic http://smallbasic.com/ もっぱらプログラミングの学習・教育用として謳われているが、実は状況によっては実務にも使えるおもしろい処理系である。 参照: 過去の投稿「Small Basic を実務で使ってみませんか?」 http://devadjust.exblog.jp/13258395/ この Small Basic、C# などの .NET 言語でふつうにクラスライブラリを作って配置するだけで、自前の機能を追加することが容易にできる。 参照: 過去の投稿「Small Basic を C# で拡張する & 配列を返すには?」 http://devadjust.exblog.jp/12758592/ 拡張ライブラリではアプリ終了時の後始末ができない?さてこの Small Basic 用の拡張ライブラリの実装だが、正味はひたすら static メソッド・static プロパティを実装、public で公開するだけである。難しいことは大してない。 ところが、である。 Small Basic 用拡張ライブラリは static メソッド・プロパティの塊でしかない。 そのため、アプリケーション終了時に何か後始末の処理を行う、というのが難しいのだ。 非static なクラスのインスタンスであれば、IDisposable を実装しておいて、呼び出しもとの責任で破棄してもらうとか、最悪、ファイナライザでなにかするとか、手段がありそうなものだ。 ところがなにせ static クラスでしかないので、拡張ライブラリそれ自身では、アプリケーションのライフサイクルを知る手立てがないのだ。 これは特に、COM サーバーなど非マネージドなリソースの解放をアプリ終了時に行いたい場合に致命的である。 Dispatcher クラスの ShutdownStarted イベントということで八方手を尽くして調べてみたら、アプリケーション終了時のイベントというものを発見。System.Windows.Threading.Dispatcher クラスの ShutdownStarted イベントだ。 WPF 界隈では常識なのかもしれないが...。 すなわち、Small Basic 拡張ライブラリの実装において、下記のコードでアプリケーション終了時の処理を書くことができる。 using System.Windows; 以上、Small Basic というだけでもニッチなネタだと思うが、それに輪を掛けて、拡張ライブラリの、しかもアプリ終了時の後始末処理の話題。 よろしければ他の #Small Basic タグの投稿もあわせてどうぞ。 Tags:#Small Basic
|