2012年5月30日水曜日

ASP.NET IIS で cron 的なジョブ処理を実行する

IISではcronのような機能はない。なので、代わりの方法についてご紹介します。

<検討案>
以下の手法が考えられる。今回推奨するのは、③。
1.普通にコンソールアプリケーションを作成し、タスクスケジューラーで実行
一番無難だが、Webサイト内の(App_Codeの)Entityやクラスなどは使えない。
プリコンパイルして参照を通すか、Webアプリケーションにしてしまうなどの対応があるが、特に前者の場合同期を取るのが面倒。

2.キャッシュの有効期限とコールバック関数を使用する
こちらで紹介されている手法。よく考えたな・・・と感嘆せずにはいられない。

ASP.NETでWindowsサービスのような機能を実装する方法

ただ、記事に書いてる通りちょっと危なっかしい。キャッシュクリアによるJOBの中断と、マルチスレッドによる複数回実行の危険性を考慮しておく必要がある。

3.Webサービスを作成して、VBScript/JScript Windows Power Shell からキックする
今回推奨案。直接サイト内に作成できるためApp_Codeのクラスが使用できるのと、起動自体はVBScript/JScriptから行うため、JOB実行はタスクスケジューラーで監視できる。

※Windows Power Shellを使用するとMSSOAP無しに実行できることが判明したので、推奨方法をこちらに切替(2012/6/21)


<推奨案:Webサービスを作成して、WindowsPowerShellからキックする方法>

以下のようなコードでサイトのWebサービスをキックできるので、これをタスクスケジューラーから実行すればよい。

<JOB用Windows Power Shellコードサンプル>
$web = New-WebServiceProxy -uri http://xxxx/yyyyy/サービス名.asmx?wsdl
$exe =  $web.サービスメソッド("引数",・・・)

参考 Windows PowerShell を使用して株価をすばやく確認する方法はありますか


<JOB用VBSコードサンプル(一応掲載)>
'Soap Toolkit 3.0を使用する場合"MSSOAP.SoapClient30"にする
Set SC = CreateObject("MSSOAP.SoapClient")

SC.ClientProperty("ServerHTTPRequest") = True
SC.MSSoapInit("http://xxxx/yyyyy/サービス名.asmx?wsdl")

'EndPointURLを指定しないとタイムアウトのエラーになることがある
SC.ConnectorProperty("EndPointURL") = "http://xxxx/yyyyy/サービス名.asmx"

SC.サービスメソッド(引数・・・)

Set SC = Nothing


※1 イントラネットから外部にアクセスする場合などで、プロキシを超える必要があるときはこれではNGになるので注意(色々なサイトで言われているConnectorPropertyによるプロキシ設定は、サービスにアクセスする前のプロキシに対して無力)。MSSOAP.HttpConnectorを使用してガチで書く必要がある。以下サイトをご参照ください。

Microsoft SOAP Toolkitを使ってJScriptでSOAP - 低レベルAPI (1) SoapConnector, SoapReader

上記サイトの補足となるが、呼び出すメソッドに引数を渡す場合は以下のようにしてやる。
soapSerializer.startElement("引数名",サービス名称空間,"","SOAPSDK1")
   soapSerializer.writeString("値")
  soapSerializer.endElement()

※2 MSSOAP.SoapClientはWindows7には入っていない?と思われる(Windows7 64bitでコードが動かないことを確認)。そのため、以下サイトからSOAP ToolKitをダウンロードする必要がある(コードを"MSSOAP.SoapClient30"にするのを忘れずに)。

Soap Toolkit 3.0

なお、64bitの場合vbsを作成するとデフォルト64bitで動作するため、32bitのdllであるこのツールを読み込むことができなくてエラーになる。
これを回避するには、32bit用のwscript/cscriptで実行をしてやる必要がある。場所は以下。

  C:\Windows\SysWOW64\wscript.exe / cscript.exe

ファイルのプロパティにあるプログラムの指定で32bitのほうを設定してやればよい。。。のだが、wscriptの方は何度指定してやっても64bitのほうになってしまうので(プログラム名が同名のため?)、32bit cscriptの方を指定してやるとうまくいく(実行できることに差はない)。

※3 windows7にこのtoolkitが入っていないのは、「これからは.NET Frameworkの方を使用してくれ」というお達しが出ているためである。そのため本ツールキットも開発が中止されているが、どうやらVB6が死に絶えるまでは大丈夫な模様。

開発ツール ライフサイクル Q&A

.NET FrameworkでのSOAPClientは事前にWeb参照を登録することが前提の開発のようで、VBScriptなどのスクリプト系言語にはかなりなじまずちょっと・・・という感じである(VBScriptから.NET Frameworkを使うこと自体は可能)

Hey.Scripting Guys

コンストラクタに引数あるときどうするの?という気もするが、渡せるのだろうか。


なお、本方式はWebサービスにアクセスする形態なので、当然サイトが生きていないとNGである点、またコネクションタイムアウトの時間を調整する必要がある点は要注意。
しかし、App_Codeとの連携と開発にVisual Studioが使えるメリットは大きいはず。



2012年5月24日木曜日

ASP.NET サイト/アプリを 無償クラウド AppHarbor にて公開する

.NETで作ったアプリを公開したい!という場合、公式クラウドAzureに無償枠はないため、作ったアプリはいつかお金を払わなければ捨て去る以外にありません。
もっと自由にアプリを作りたいが金はない、という場合.NETのPaaSであるAppHarborの使用をお勧めします。

AppHarborは.NETアプリケーション用のクラウド環境で、無料から使用できSQLServerなどのDBもつかえます。また、Azureのように「Azure専用」にアプリケーションを作成する必要がなく、いつもどおり作ったアプリケーションを配置することが出来ます(Azureをxxしているわけでは、ない)。

<AppHarborの使用手順>
1.Windows用Gitのインストール
以下サイトを参考にインストールを行います。
Set Up Git

途中で”コマンドプロンプト(cmd)からも使えるようにするか”と聞いてきますので、これはYesにしておいたほうが便利です。

2.Webサイト/Webアプリケーションを作る
いつもどおりWebサイトやWebアプリケーションを作ります。
※Webアプリケーションでないと駄目だという情報が幾つかありましたが、少なくともASP.NETの通常のWebサイト(MVCでない)はデプロイ可能でした。

3.ローカルリポジトリを作成する
コマンドプロンプトでWebサイト/Webアプリケーションのフォルダに移動し、
git init
を実行します。

~いろいろファイルを編集~

4.変更内容をローカルにコミットする
以下コマンドで、変更をローカルにコミットします。
git add .
git commit -m "my first commit"

※このあたりの詳細は、Gitの使い方を参照してください。

5.ローカルのコミットをAppHarborに反映する
AppHarborでは、事前にアカウントをつくりアプリケーションを作っておきます。
アカウントを作った後のトップ画面で、Create new application の箇所にアプリケーション名を入れてCreateボタンを押せばOKです。名前は2で作成したものと同名にしておいたほうが懸命と思われます。

AppHarborでアプリケーションが作られると、以下のようなメニューが表示されると思います。
一番下にある「REPOSITORY URL」をクリックすると作成したアプリケーションのリポジトリがクリップボードにコピーされます。その内容を、

 git remote add appharbor xxxx

のxxxxの部分と置き換えてコマンドを実行してください。



現時点でのイメージは以下のようになっています。
AppHarbor上にリポジトリをつくり、そのremote宛先をaddで登録したところです。

 宛先の登録が終わったら、以下コマンドで発行を行います。

git push appharbor master


このコマンド後コンパイルが走り、しばらくするとWebサイトが発行されます。先ほどのメニューのHostnamesというところから、作成されたWebサイトのアドレスが参照できます。

発行後ファイルに変更を加えた場合は、手順4からの作業(登録除く)の繰り返しになります。
Gitのコマンド的には以下の通りです。
~ファイル変更~

git add .
git commit -m "my second commit"
git push appharbor master

※commit時のメッセージ内容は自由です。


※その他※
・PreCompileについて
AppHarbor上でプリコンパイルがデフォルトオンになっているせいか、App_Codeのフォルダがサイトに含まれているとエラーになります。
これを回避する場合、SettingsにあるBuildの箇所で、プリコンパイルをオフにしてください。

・SqlServer/EntityDataFrameworkの使用について
アドオンを追加することで可能になります(20MまでフリーのDBあり)。
接続文字列はConfiguration Variableを使用するか、SqlServerの詳細画面から確認可能です。


Entity Frameworkを使用する場合は、Entity Framework metadata:のところにEntityDataFrameworkを使用するとweb.configに勝手に挿入されるconnectionStringの"res:~.msl"の部分を設定するとEntityFramework用の接続文字列を作成してくれるので、それをweb.configに設定すればきちんと動きます(自動で変換してくれるといううわさも聞いたが、そんなことはなかった)。

動作は.NetFramework4.0/EntityDataFramework4.0で確認しました。


・Git Hubについて
せっかくGitを使っているので、Git Hubに登録するのはアリだと思います。Git Hubはソースコードを共有するためのサービスで、Rubyなどのプロジェクトではかなり良く使われています。
Git HubからAppHarborにつなぐことも出来るようなので、これを機会に試してみても良いと思います。



GIMP 2.8

GIMPが、3年半ぶりにメジャーバージョンアップ!

シングルウィンドウモードへの対応はうれしいですね ^^

http://www.gimp.org/release-notes/gimp-2.8.html


2012年5月8日火曜日

NUnit で ASP.NET WebForm のサイトをテストする

前回の記事でまとめた内容を、プロジェクトテンプレートとして使えるようにしました。

前回:ASP.NET WebFormでNUnitによるUnitTest環境を構築する

プロジェクトテンプレート ※Visual Studio拡張機能からもインストール可能

NUnitWebForm


苦労したのは、自動的にNUnitを起動する箇所と、対象サイトをコンパイルするバッチ。
カレントフォルダの取得に相当苦しめられたが何とかこれでいけると思う。

コンパイルオプション以外でもちゃんとマクロを使えるようにしてほしい今日この頃。

Windows バッチファイルでカレントディレクトリを取得する

ようやく取得できた・・・ので、方法を記載しておきます。

@echo off
setlocal
REM バッチファイル実行パス取得(カレントディレクトリの場合、%CD%に変更)
SET STR="%~dp0"
if %STR%=="" exit

REM パス中の空白を#に変換
SET STR_NO_BLANK=%STR: =#%
REM パス区切り文字(\)を空白に変換
SET STR_TOKENS=%STR_NO_BLANK:\= %

REM 空白パスのためにつけていた二重引用符を削除(しないとforがうまくいかない)
for %%i in (%STR_TOKENS:"=%) do (
  SET TOKEN=%%i
)

REM 最終フォルダ=カレントディレクトリを取得(#にしていた空白を再変換)
echo %TOKEN:#= %

endlocal


※2012/05/14追記
jak-sanよりコメントを頂き、上記内容を修正すると共にもっと簡単な方法を追記します。

@echo off
setlocal

set x=%~dp0
REM パス末尾の\を除去し終端ディレクトリをファイル名のようにする(C:\hoge\ -> C:\hoge)
set x=%x:~0,-1%

REM ファイル名部分を取得する~nで末端ディレクトリを取得する
for /F "delims=" %%a in ('echo "%x%"') do echo %%~na

endlocal

え?~nとかってどういう意味?という場合下記のサイトを参考にしてみてください(jak-sanさんのサイトでなくてすみません・・・なかなか見つからなかったもので・・・)。

2012年5月3日木曜日

Visual Studio 2010 express に SQLite を統合する

すばらしく時間がかかったがようやく設定が終わったため、メモ。おそらくこんなに苦労したのはx64環境だからで、x32なら普通にできる可能性大。

1.SQLite ADO.NET Providerのダウンロード/インストール
最近のリリースにはなぜかProviderが入っていないので、昔のバージョン(1.0.66)をまずダウンロードする(公式サイトのリンクが切れているのでsource forgeから落とす)。
ver 1.0.66

2.最新版のSystem.Data.SQLiteのダウンロード/インストール
x32(x86)とx64両方落とす必要がある点に注意する(パソコンがx32ならx64はいらないかもしれない)。ダウンロードはこちらから。Setup for xxx となっているものを、それぞれダウンロードする。

※ダウンロードするのはbundleとついているほう。System.Data.SQLiteにはネイティブのコードが含まれており、ネイティブ分をマージした版(bundle)か切り出した版(Interop.dllに分かれている?)か選ぶことができる。
VisualStudioから使う際、分割版はどうもうまくいかないのでbundleで行う。

インストール時、スタートアップにメニューを追加するかどうかの後に、インストール後の作業として global assembly へ追加するかどうかなどのチェックボックスを入れる画面になる。ここで、x86のインストール時は全てチェックを入れておき、x64のときは初期提案のままとした。
これに意味があるかはわからないが、Visual Studio 2010 Expressがそもそもx86で稼動しているので、x86側の設定を優先するようにした。


3.最新版dllの移行
後は引越し作業が待っている。Providerをインストールしたフォルダ(C:\Program Files (x86)\SQLite.NET)のbinを、最新版のx86 System.Data.SQLiteのbinで上書きする。そして、bin/x64のフォルダを同じく最新版のx64 System.Data.SQLiteのbinで上書きする。
※念のためbinフォルダのバックアップを取っておくことを推奨。

これで作業は完了。Visual Studioを起動すればサーバーエクスプローラーからSQLiteを追加できるようになっているはず。
ただ、データソースの追加としたときにConnectionStringの設定画面しか出てこないような場合は設定がおかしい。ここから先は色々試したので何が正解かわからないが、とりあえず以下を試せば何とかなると思われる。

 3.1 デザイナのリフレッシュ?
 C:\Program Files (x86)\SQLite.NET\bin\Designer内のSQLite.Designer.dllをx86側の最新版に置き換え、install.exeを実行する。
途中System.Data.SQLite.dllの場所を何度も聞かれるが、恐らく永久に聞いてくるので一回入力したらキャンセルする。


 3.2 machine.configのDbProviderFactoriesセクションへの接続文字列の追加
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Configにあるmachine.configにSqliteの接続文字列を追加する(test.exe.configの設定をコピーすればよい)。x64の場合、64bit版.NET Frameworkの側にも設定を追加しないといけない点に注意。


3.2 /resetskippkgs オプションでVisual Studioを起動する
 パッケージのキャッシュが残ることがあるらしいので、これでリフレッシュ。

逆に、machine.configへのDataProviderFactoryの追加・C:\Windows\assemblyへの追加を試みる、といったことは意味がなかった。そして、1.0.66のインストールだけではうまく動かないことも確認済み。やはり最新版をインストールして対応させる必要がある。


これでうまくいく・・・と思う。


なお、これはあくまでSQLiteを.NETから使えるようにしただけなので、実際にテーブルを作ったりデータを入れたりという操作は別途行う必要がある。
サーバーエクスプローラーが使えればそこからでも可能だが、他のツールとしてはSQLiteAdminが有名なようだ。


4.プロジェクトでの使用
System.Data.SQLite/System.Data.SQLite.Linqをコピーしてきて参照設定をし、使う。
コピーしてくるのが面倒、という場合はまずインストールフォルダへ参照設定を行い、その後参照設定のプロパティでローカルコピーをTrueにする。
参照は64bitと32bitどちらなの?というのはPCの環境に合わせるのが吉か。少なくとも、NUnitで動かす際はPC環境とあったdllに参照を通していないと例外が発生した(x86.exeの方で動かせば動くかもしれないが)。
エンティティデータモデルでもきちんと使うことが可能。


参考サイト

SQLite on Visual Studio 2010 Setup Instructions