2010年3月31日水曜日

jQueryでUIをブロックできるPlugin

jQueryでUIをブロックできるPluginを解説する。使ってみた感じは下図を参照して欲しい。


全体的に薄いグレーになっていて真ん中にメッセージが出ているのが見てとれると思うが、今回解説するPluginを使用するとそれが実現可能だ。使い方はいたって簡単。こちらからjquery.blockUI.jsをダウンロードして、下記のコードをペペッとscriptタグ内に貼り付ければ良いだけ。

jQuery(document).ready(function() {
 $.blockUI({
  title: 'Tips',
  message: 'メッセージだよー',
  css: { 
   padding:'20px'
  }
 });
 $('.blockOverlay').attr('title', 'クリックで解除').click($.unblockUI);
});

他にも多様な使い方があるのでデモページを参照して欲しい。

2010年3月30日火曜日

ASP.NET MVCでELMAHを使う

エラーのログをどうするか、というのはアプリケーションの永遠の課題だが、ASP.NETには優れたソリューションがある。それがELMAHだ。ELMAHはError Logging Modules and Handlersの略称だ。公式サイトはこちら

で、Elmahを使うと何ができるの?というのは下図をみてもらえればわかると思う。





ELMAHを設定した後にhttp://localhost:****/elmah.axdへアクセスすると上図のページが参照できる。一つ目はELMAHにハンドルされたエラーの一覧だ。二つ目の画像はそのエラーリストのうちの詳細情報になる。そう、ELMAHはASP.NET開発者が開発中に良く見かける黄色いエラーページ(いわゆる「Yellow screen of death」だ)の内容をそのまま保持管理してくれるのだ。

他にも、エラーが発生したことを通知してくれるメール機能やエラーの種類をフィルターする機能もある。また、エラーログの保存先として、SQL Serverはもちろん、Oracle, SQLite, Microsoft Access, VistaDB, XML, RAM(メモリ上)が選択できる。

さらに嬉しいことに導入はいたって簡単。Web.configにぺぺっといくつかの項目を記述して、ELMAHのDLLをbinへコピーするだけで(最もシンプルな構成にした場合は)すぐに動作する。

それではここから導入方法を解説する。今回はログのバックエンドとしてSQL Server 2008, サーバはIIS7, メール機能の有効化を行う。
(注意!これはASP.NET MVC用の導入手順なのでASP.NETと微妙に違います)

  1. まず前述の公式サイトからELMAHの最新版をダウンロードしElmah.dllを導入したいアプリケーションのbinフォルダへコピーする。
  2. 続いてweb.configを開き(下方にあるsample.configを参照) sample.configの内容をコピーする。
  3. このDTDをELMAHのログをインストールしたいDatabase上で実行する(実行時に互換性がうんたらかんたらとメッセージがでるが無視して構わない)。


-sample.config-(必要な箇所以外は省略してあります)
<configuration>
 <configSections>
  <sectionGroup name="elmah">
   <section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah"/>
   <section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah"/>
 </sectionGroup>
</configSections>

<elmah>
 <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="ApplicationServices" />
  <errorMail from="***"
   to="***"
   subject="***"
   async="false"
   smtpPort="***"
   smtpServer="***"
   userName="***"
   password="***" />
</elmah>
<connectionStrings>
 <add name="ApplicationServices" connectionString="***"/>
</connectionStrings>
<system.web>
<httpHandlers>
 <add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah"/>
</httpHandlers>
<httpModules>
 <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah"/>
 <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah"/>
 <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah"/>
</httpModules>
</system.web>
<system.webServer>
 <handlers>
 <add name="Elmah" verb="POST,GET,HEAD" path="elmah.axd" preCondition="integratedMode" type="Elmah.ErrorLogPageFactory, Elmah"/>
 </handlers>
 <modules runAllManagedModulesForAllRequests="true">
  <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah"/>
  <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah"/>
  <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah"/>
 </modules>
</system.webServer>
</configuration>


ここまでできたらhttp://localhost:****/elmah.axdへアクセスしてみよう。一つ目の画像の画面が表示され、「No errors found.」と表示されていたら成功だ。さらに何か適当なURLをたたくなどしてエラーを起こしてから、elmah.axdをリフレッシュし、それがログされているのを確認しよう。

また、HandleErrorAttributeと一緒にELMAHを使いたい場合はこちらのページを見てもらいたい。開発者であるAtif Aziz氏みずから解決策をコメントしてくれている。

今回解説していない機能の詳細についてはこちらを参照して欲しい。MSDNにもELMAHの解説が日本語であるのでそちらを参照するのも良いだろう。

2010年3月27日土曜日

JavaScriptの勉強本

実際にこの本を手に取ったのは2年以上前のことで、そのときは英語版を読んだのだが、それまでなんとなくJavaScriptを使ってなんとなく処理をしていたので、どういうコンセプトの言語なのか、イベントのハンドリング、メモリの確保・解放などを深く考えずにやっていた。この本ならプログラム初心者でも1から学べるし、JavaScriptでのオブジェクト指向プログラミングのやり方も解説してくれる。jQueryでPluginを作りたい人や、JavaScriptで大規模なWeb Ajaxアプリケーションを作りたい人には必須の知識なので読んでおいて損はないだろう。



またReferenceとしても優秀なので、手元にあると便利な一冊だ。

2010年3月26日金曜日

Http GetでJsonをリクエストするとエラーになっちゃう

ASP.NET MVC 2もリリースされて一月ほどたち、正式リリースされてから機能にはキャッチアップすれば良いとPreview, RCと6回もリリースされているものをほぼすべて無視してきたので、MIX10でWhat's New in Microsoft ASP.NET MVC 2があったのには助かった。で、他のビデオやブログでもASP.NET MVCからMVC 2への移行はなんの問題もなくできる、とあったのだが、前述のVideoの中で大変気になる部分があった。それが、今回のブログポストのタイトルにもあるように、Http GetでJsonを取得(正確には返却)しようとするとエラーになるというところだ。まさにWTF。

これはMVC 2でJSONまわりのセキュリティが引き締められたために発生するエラーで、回避策は下記の通り。

// SomethingController.cs
public ActionResult GetJson()
{
 var hoge = "hoge";
 return new JsonResult { Data = hoge, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}

JsonResultのJsonRequestBehaviorにJsonRequestBehavior.AllowGetを指定してやれば良い。まぁJsonを返却する場合はPOSTでリクエストしろよ、という話かもしれないが、jqGridをがんがんに使っているプロジェクトでは無理な話なので、MVC 2に移行するときはしこしこと地道に書き直すしかない。そういえばjqGridの使い方を解説しようとずっと前に思い立ったままになっていたので、良い機会なのでデモページへのリンクを載せておく。

jqGrid demo

検索結果なんかを表示するのにひっじょうに便利なので一見することをおすすめする。

2010年3月24日水曜日

SQL Server 2008で初めてDBをリストアしたときの罠

自分のPCに環境を構築するさいにDBのバックアップファイル(.bak)を受け取ってリストアして利用することがままあると思う。そんな際にログインユーザ周りでうまくいかないときがあるので解説する。

初めてDBをバックアップファイルからリストアしたときに高確率で遭遇するのが、そのDBのユーザでログインできないという現象だ。下記に事例をあげる。

<例>
SouthWindというDBをリストアしたとする。SouthWindのユーザとしてdb_ownerのhogeがいる。開発中はhogeを使ってTableのデザイン変更などを行いたい。そのため、<Your PC>/Security/Loginsにhogeを追加しDefault databaseをSouthWindとする。しかし、hogeでいざログインしようとするとDefault databaseがうんたらかんたらというエラーが出てログインできない。WTF。

SouthWindのUsersにhogeが追加されていないせいかとあたりをつけて、<Your PC>/SouthWind/Security/Usersを参照するもすでにhogeがいる。すでにhogeがいるのにログインできない。WTF again。

ということがまま起こるのだが、これはLoginsのhogeと<Your PC>/SouthWind/Security/Users配下のhogeの紐付けが切れてしまっているために起こる。なので下記のクエリを実行して権限をむりくり付与してやればよい。

ALTER AUTHORIZATION ON DATABASE::SouthWind TO hoge

これで問題なくログインできるはずだ。また、まれにログインはできるがデータベースダイアグラムを作成できない場合がある。その場合も上記のクエリを実行すると解決する。

ZuneにWindows 7をインストールする方法

iTunesにも飽きたのでZuneを次のミュージックプレイヤーにしようと思い立ち、Installerをダウンロードするところまではよかったのに、exeをたたくと途中でエラーになって動かない。「Error: 0x80070002 Windows 7 portable device update cannot find blah blah blah」と訳の分からないことをのたまう。しょうがないので「Zune error code 0x80070002」で調べたら見当違いのエラーばかりひっかかる始末でMSらしくError codeの用をまったく成していない。で、さらに調べていたら解決策を見つけたので下記に。

  1. ZuneのInstallerのexeを右クリック→プロパティをクリックする
  2. 互換性タブを開く
  3. 下の画像のチェックボックスにチェックをしてプロパティウィンドウを閉じる(Vistaにしてね)
  4. exeを実行する


Windows 7は何かと手がかかる。しかし、Zuneかっちょいいぜっ!ただ、Zuneの検索ボックスで日本語が入力できないのは気のせいかな・・・?

Windows Vistaから7へのアップグレード時の互換性の問題

ずいぶん前にWindows 7のアップグレードDVDをDellのキャンペーンで入手していたのだが、アップグレードでトラブルのも面倒くさいため長いことほっぽいていたのだが昨日ついに使ってみた。で、案の定トラブルがポツポツとあって、結構面倒くさかったので以下に解決方法を記しておく。


~Vistaから7へ~

アップグレードをしようとDVDを入れてexeを実行すると、いくつかのアプリケーションがそのままでは7上で動作しないのでアンインストールしろと指示されるのでその通りにする。

削除するように指示されたアプリ達。
・iTuens
・SQL Server 2008
・Realtek tools(?詳細失念)
・Daemon tools lite
(もう一つ消すようにとアプリを指示されたのだが失念)

指示されたアプリを削除してからアップグレードを行うとすんなりと行えた。それでも3時間ほどはかかったけれど。


~Daemon Tools Liteをいれる~

削除してしまったSQL Server 2008をインストールするためにDaemon Tools Listが必要なのでインストールしてから実行すると「SPTDのバージョン1.60以上が必要です」とかなんとか言われてエラー終了してしまう。意味が分からないので色々と調べたら同じ状況に遭遇している人が多数いたので、その中で有効だった方法を下記に。ちなみに元情報はこちら

(注意!レジストリをいじるので下手をするとWindowsが正常動作しなくなるので、自己責任でお願いいたします)

  1. SPTDのインストールexeをここからダウンロードする。あわせてDaemon Tools Liteをアンインストールしておく
  2. レジストリエディタ(*)でHKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\sptdにある「Start」キーの値を4にしてから再起動する
  3. 再起動後、再度レジストリエディタを開き、HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\sptd\cfgを右クリックし、アクセス許可を選び、フルコントロールにチェックをする
  4. HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\sptdにあるキーをすべて削除してから再起動する
  5. 1でダウンロードしたexeを実行しインストールをすると再起動が要求されるので再起動する。再起動後に、再度1でダウンロードしたexeを実行し、「Uninstall」のボタンが有効になっていれば、正常にインストールされている。されていなければ、再度2から実行し、5を飛ばして6へ進む。(注意!下記の手順は前述したサイトに載っていましたが、私は5までで正常動作したので下記の手順は実行していません)
  6. レジストリエディタを再度開き、「daemon」で検索し、見つかったものをすべて削除する。一巡だけでなく数回繰り返すこと。すべてなくなったら再起動をし、5の手順を実行する。

*ウィンドウズボタン+Rで「ファイル名を指定して実行」ダイアログを出して、名前のところに「regedit」と入力するとレジストリエディタが表示さ れる。

これでSPTDが正常にインストールできたので、Daemon Tools Liteをインストールし実行することが可能となる。

2010年3月16日火曜日

複数選択を行える便利なjQueryのリストプラグイン ~ multiselect

複数の項目を選択できる便利なjQueryのプラグインを以前使ったので、ASP.NET MVC上でどのように実装するかを解説する。実際に動作しているものは下図の通り。


公式サイトはこちらなのだが、今回は機能がより豊富なYanick Rochon氏作成のこちら(リンク死亡確認 by 王大人:2011/4/23。対応リンクは下記参照のこと)のバージョンを使用する。Referenceも前述のサイトにあるので必要に応じて参照して欲しい。

更新:2011/4/23
こちらのGitからAjax検索対応のMultiselect pluginが取得できる。対応の説明サイトはこちら
Ajax未対応のMultiselect pluginはこちらから取得できる。
新しく解説したのが下記。
複数選択を行える便利なjQueryのリストプラグイン その2
更新ここまで

あわせて下記のライブラリも必要なのでそれぞれ取得して欲しい。
jquery-ui
jquery.tmpl
jquery.blockUI

aspxの実装は下記の通り(省略してあります)。

<link href="../../Content/Multiselect/ui.multiselect.css" rel="stylesheet" type="text/css" />
<script src="../../Scripts/Multiselect/jquery-ui-1.7.1.custom.min.js" type="text/javascript"></script>
<script src="../../Scripts/Multiselect/jquery.blockUI.js" type="text/javascript"></script>
<script src="../../Scripts/Multiselect/jquery.tmpl.1.1.1.js" type="text/javascript"></script>
<script src="../../Scripts/Multiselect/ui.multiselect.js" type="text/javascript"></script>

<script type="text/javascript">
$(document).ready(function() {
    $("#clubs").multiselect({ remoteUrl: '/Admin/GetClubs/' });
});
</script>

<select id="clubs" class="multiselectForClubs" multiple="multiple" name="clubs">
</select>

画像を参照してもらえば分かると思うが、プラグイン右上に検索用のテキストボックスがある。今回は何か入力された際にサーバサイドで検索を行いたいのでmultiselectのオプションにremoteUrlを設定している。remoteUrlを指定しない場合はクライアント上でのフィルタリングが有効になる。サーバサイドで呼び出されるのはremoteUrlで指定したAdminControllerのGetClubsメソッドだ。

AdminControllerの実装は下記の通り。

public ContentResult GetClubs(string q){
 var clubs = _service.Clubs.Where( Logic is here ).ToArray();
 var results = clubs.Length > 0 ? string.Join("\n", clubs) : string.Empty;
 return Content(results);
}

検索テキストボックスに入力された内容は引数qとして取得できる。初期状態でのremoteUrlの戻り値はValue=Textで一行ごとにひとつのoption要素を想定しているので、それに当てはまるように整形している。独自のデータ構成で返却したい場合はdataParserオプションを使用すれば可能だ。今回は文字列をそのまま返却するためにContentResultを使用している。

2010年3月2日火曜日

Mr. Gengo(英単語勉強用アプリ)作成シリーズ ~ ListBoxにネストしたListをBindする方法

下記の画像のようなネストしたListのBindをXAML上で行う方法を解説する。



Mr. Gengoのデータ構造は下記のようになる。

// 以下、このブログポストのコードは必要な箇所以外をすべて省略している
public class Entry
{
   public ObservableCollection<entrysense> Senses { get; set; }
}

public class EntrySense
{
   public ObservableCollection<gloss> Glosses { get; set; }
}

public class Gloss
{
   public string Text{ get; set; }
}

では実際のXAMLとDataContextに渡すクラスであるJMDictModifierPresenterを見てみよう。

public class JMDictModifierPresenter
{
   public ObservableCollection<Entry> CurrentEntries { get; set; }
}

<ListBox
    ItemsSource="{Binding CurrentEntries}"
    IsSynchronizedWithCurrentItem="True" >
   <!--省略-->
</ListBox>

<ListBox
    ItemsSource="{Binding CurrentEntries.CurrentItem.Senses}"
    IsSynchronizedWithCurrentItem="True" >
   <!--省略-->
</ListBox>

<ListView ItemsSource="{Binding Path=CurrentEntries.CurrentItem.Senses.CurrentItem.Glosses}" >
 <ListView.View>
  <!--省略ここから-->
  <TextBox Text="{Binding Text}" />
  <!--省略ここまで-->
 </ListView.View>
</ListView>

ポイントはItemsSourceにBindしているCurrentItemだ。一つ目のListBoxのItemsSourceにBindしているのはDataContext(JMDictModifierPresenter)のCurrentEntries、二つ目のListBoxのItemsSourceではCurrentEntriesで現在選択されているアイテムのSensesが取得したいのでCurrentEntries.CurrentItem.Sensesとしている。ListViewのItemsSourceも同様なので説明は不要だろう。

また、それぞれのListBoxでIsSynchronizedWithCurrentItem=Trueを設定しておかないと予期した動作にならないので忘れずに設定しておこう。

英単語勉強用アプリ作成シリーズ ~ ListBoxでの思わぬ落とし穴

基本機能はほぼ網羅し、着々とアプリのほうは仕上がりつつあるのだが、こまごまとしたところで問題があるので暇を見つけてはプチプチとつぶしている日々の中で思わぬ落とし穴に数日間はまったのでそれの解説をしようと思う。


上記の画像にあるように、英単語勉強用アプリ(を改めてMr. Gengo)は辞書データを自分の好みの形へ改修できるようにしてある。それが上記のJMDictModifierなのだが、かなり困った問題があった。それは「Add Entry」「Add POS」でそれぞれのListBoxへアイテムを追加すると、追加されたアイテムがそれぞれのListBox内でまとめて選択されてしまうという現象だった。その現象は下記の画像の通り。


Ohとうならざるを得ない現象なのだが、複数行を同時に選択してしまうのはひとまず良しとして(SelectionMode=Singleにしているのでアプリ的にはまったくよくないのだが)、もっと深刻な問題はDeselectできないこと。選べるのに一度選ぶとはずせない。アイテムの追加はXAML上ではなくプログラム上で行っているのでその追加のコードが悪いのかと色々と試してみたけれど効果がない。まぁ悪いも何もObservableCollectionに対してアイテムを追加しているだけのプログラムなので試す方法も限られている。仕方がないのでGoogle先生に尋ねてみたら同じような現象で悩んでいる人が居た。

WPF ListBox Selection Problem when changing an item - Stackoverflow

実装している動作は違うようだが、発生している現象は同じようだ。それなので回答に寄せられている方法を色々ためしてみた。しかしどれも効果がない。それはそのはずで、そもそもIsSynchronizedWithCurrentItem=Trueってのは言われなくともやっているし、CollectionViewSourceを作れ!というのも元になるListをObservableCollectionでラップしてからBindしているのでやろうとしていることは同じだ。

万策尽き果てて困りつつも、ポチポチと動かないときの動作確認をしていたら、あるときは動作することを見つけた。それは、アイテムに表示されている内容がすべて異なる場合に正常動作していた。The fuck?と思いつつもどうやらListBox内でアイテムを一意に特定することができずに、同一データ内容のアイテムがまとめて選択されているようだった。「えー?!ListBox内のアイテム比較をデータ内容でやってるのー?まじー?ありえなーい」と驚愕していたら自分の過ちに思い至った。過ちは以下のコード。EntryクラスはListBoxのItemsSourceにBindされているObservableCollectionのアイテムクラスだ。

public class Entry {
// ---省略---
        public override bool Equals(object obj)
        {
            if (obj is Entry)
                return (obj as Entry).Kanji == this.Kanji;
            return false;
        }
// ---省略---
}

ひゃーーー!!!!!恥ずかしいっ!!!アイテムの比較をデータ内容でやっているのは私でしたっ!!

他の箇所でEntryクラスのデータ内容で比較するプログラムがあったので格好つけて「Equalsクラスを上書きしてスマートに比較するかな!キリッ」とかやったらご覧の有様でした。こんなくだらんことで四日間ほども悩んでいたのがアホらしすぎて泣けてくる。