つい最近ReflectorがRedgateという会社に買収されたようですな。一応無料版は残していく方向のようですが、有料版にはどんな機能が付いてくるというんでしょうか。楽しみであり少々心配でもあるような。
カテゴリ「.NET」の過去ログ
AJAXが主流になってきている昨今である。サーバ側のコードだってJavaScriptから簡単に呼び出せるようにしてくれたのがMicrosoftのAJAXだ。利点はPostBackをせずに、つまり、ページのリフレッシュをせずに動的にHTMLの要素を表示し、ユーザの使い勝手をよくしようとするものだ。この記事ではウェブサービスから返されたHTMLの文字列をJavaScriptで読み込み、それを動的に表示する方法を簡単な例で紹介する。
まずはASP .NETのプロジェクトに.asmxのファイルを追加する。ウェブサービスだからといって別途ウェブサービスのプロジェクトを用意する必要はない。この例ではSimpleService.asmxと名前をつける。そして下のようにコードを書く。
1: Imports System.Web.Services
2: Imports System.Web.Services.Protocols
3: Imports System.ComponentModel
4: Imports System.Web.UI.HtmlControls
5: Imports System.IO
6: Imports System.Text
7:
8: ' To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
9: ' <System.Web.Script.Services.ScriptService()> _
10: <System.Web.Services.WebService(Namespace:="http://tempuri.org/")> _
11: <System.Web.Services.WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
12: <ToolboxItem(False)> _
13: <System.Web.Script.Services.ScriptService()> _
14: Public Class SimpleService
15: Inherits System.Web.Services.WebService
16:
17: <WebMethod()> _
18: Public Function GetHtml() As String
19: ' まずはクライアント側に返したいHTMLをSystem.Web.UI.HtmlControlsにあるクラス群を使って作成する。
20: Dim cell1 As New HtmlTableCell()
21: cell1.InnerText = "Hello Cell1"
22:
23: Dim row1 As New HtmlTableRow()
24: row1.Cells.Add(cell1)
25:
26: Dim table As New HtmlTable()
27: table.Rows.Add(row1)
28: table.Border = 1
29:
30: ' ここからHTMLコントロールを文字列に変えるプロセス。
31: Dim sb As New StringBuilder()
32: Dim sw As New StringWriter(sb)
33: Dim htmlWriter As New HtmlTextWriter(sw)
34:
35: table.RenderControl(htmlWriter)
36:
37: Return sb.ToString()
38:
39: End Function
40:
41: End Class
上のコードをもうちょっと解説する。13行目のSimpleServiceクラスに対するAttributeは追加してやらなければいけません。これはJavaScriptから呼び出すことを可能にしますよというAttributeだ。そしてGetHtmlというFunctionを作成しStringを返すようにしてやる。もちろんWebMethodのAttributeをつけてやるのも忘れないようにする。そしてTableを作成してHtmlTableのオブジェクトをRenderControlというメソッドを実行するとStringBuilderにそのHTMLが入っているのでそれを返してやるだけだ。これでウェブサービスの準備は完了だ。
次にクライアント側だ。ASP.NETのプロジェクトを作成するとDefalt.aspxがついてくるのでそれを使う。
ASP.NETでAJAXを使うには必ずそのページにScriptManagerを追加してやらなければならない。これはformタグ内に入れてやるといい。そのScriptManager内にはServicesというコレクションが存在し、そこに先ほど書いたSimpleService.asmxへの参照を追加してやる。
<asp:ScriptManager runat="server" ID="ScriptManager1">
<Services>
<asp:ServiceReference Path="~/SimpleService.asmx" />
</Services>
</asp:ScriptManager>
これでウェブサービスを直接JavaScriptから呼び出せる。
Default.aspxにHTMLボタンを貼り付けてそのonclickのイベントハンドラーで次のようなJavaScriptを書く。
function Button1_onclick() { AjaxTest.SimpleService.GetHtml(OnComplete, OnTimeOut, OnError); return true; }
実際にコードをVS2008上で書いてみるとJavaScriptのインテリセンスが表示されるので便利だ。通常はJavaScriptからウェブサービスへのコールは非同期で行われるので上のようなコードになる。それではOnCompleteを見てみよう。
function OnComplete(arg) { alert(arg); var divLayer = document.getElementById("divHtmlPlaceHolder"); divLayer.innerHTML = arg; }
ここではウェブサービスから受け取ったHTMLを一度alertで表示させて既存のdivタグ内(divHtmlPlaceHolder)に入れてやるのだ。OnErrorとOnTimeOutも下に貼り付けておこう。
function OnTimeOut(arg) { alert("Call timed out"); } function OnError(arg) { alert("Error happened"); }
これで簡単にサーバ側のコードがJavaScript側から呼び出せる。
更新:Fiddler2でHTMLトラフィックを見てみました。Responseはこんな感じです。XMLを使わずコンパクトでいいんじゃないでしょうか。
HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.0
X-AspNet-Version: 2.0.50727
X-Powered-By: ASP.NET
Date: Sun, 27 Jul 2008 23:47:37 GMT
Content-Length: 153
{"d":"\u003ctable border=\"1\"\u003e\r\n\t\u003ctr\u003e\r\n\t\t\u003ctd\u003eHello Cell1\u003c/td\u003e\r\n\t\u003c/tr\u003e\r\n\u003c/table\u003e\r\n"}
あるMS社員のブログを読んでいたら、実はVisual Studioと.NET FrameworkのHotFixはVisual Studio and .NET Framework Hotfix Public Availability Programというのからダウンロードができるそうです。どうしても他に解決方法がない場合は大変助かりますね。
Twitter用のC#ライブラリ見つけました。まだ全然試してないですけど、参考程度にはいいかなと。カスタムコマンドレットのGet-TwitterとかSend-Twitterとか作ってみたいっす。
仕事をしていてちょっとしたことを自動化したいことはよくあることだ。そのためにWindowsクライアントソフトを作成するのはもちろんのことコンソールアプリを書くのだってちゃんと書こうとしたら面倒だ。というのはどのようにパラーメータを定義してそれをちゃんと読み込むメカニズムを作って、そしてそれに対するチェックも怠ってはいけないからだ。これをきちんとこなすには、ちょっとした作業を自動化したい場合には、結構な労力だ。(だったらPowerShell使えって?)そこでMSBuildのカスタムタスクを利用して簡単に.NETのコードを実行することができる。
【必要なもの】
- Visual Studio 2005かVisual Studio 2008(今回はVisual Studio 2008を使用する)
- ここではVBを使うことにするが、手順はC#でもほとんど変わらない。
【準備】
- クラスライブラリを作成。CustomTaskと名前をつける。プロジェクトの名前は必ずしもCustomTaskでなくても良い。
- クラスライブラリの参照にMicrosoft.Build.Utilities.v3.5とMicrosoft.Build.Frameworkを追加する。Visual Studio 2005かVisual Studio 2008をインストールしていればこれらのアセンブリはインストールされているはず。Visual Studio 2008の場合はプロジェクトを作成するときに.NET Framework 2.0か3.0か3.5にターゲットを変えることができる。今回は3.5をターゲットにやってみる。
【コードを書く】
コードを書く準備ができたので、上で作成したプロジェクトにクラスを追加する。Loggerというクラスを追加して下のようなコードを書いてみよう。
Imports Microsoft.Build.Utilities Imports Microsoft.Build.Framework Public Class Logger Inherits Task Public Overrides Function Execute() As Boolean Console.WriteLine("Hello World") Return True End Function End Class
LoggerクラスはTaskを継承する。もちろんクラスの名前は用途によってどんな名前にしても可。TaskクラスはMicrosoft.Build.Utilities.Taskに存在する。実行したいコードをExecuteメソッド内に書く。基本はこれだけなのだ。ExecuteメソッドはBooleanの値を返すのでExecute内のコードの実行が問題なく終わったらTrueを返すようにする。Falseを返すとMSBuildはビルドが成功しなかったとみなすので注意。ではどうやってそれを実行するかを次に説明していくことにする。
【MSBuildのXMLを作成する】
次にMSBuild用のXMLファイルを上で作成したプロジェクトに新規に追加する。SchemasにMSBuild.xsdを読み込ませる。するとMSBuild用のXMLデータを作成する際にインテリセンスを使用できるので便利。下のようにXMLを作成してみよう。
<?xml version=”1.0″ encoding=”utf-8″ ?>
<Project xmlns=”http://schemas.microsoft.com/developer/msbuild/2003″>
<UsingTask AssemblyFile=”C:\Development\CustomTask\CustomTask\bin\Debug\CustomTask.dll” TaskName=”CustomTask.Logger”/>
<Target Name=”Jikkou”>
<Logger />
</Target>
</Project>
上のXMLファイルを解説することにしよう。<Project>が一番上の層になる。<UsingTask>のタグ内にはMSBuildから呼び出すアセンブリのパス(AssemblyFile)とそのアセンブリ内で使用するクラス(TaskName)を指定する。そして<Target>タグに適当なNameをつけて、<Logger />と実行するクラスの名前で子ノードを追加してやる。これで準備は完了だ。後はVisual Studioのコマンドプロンプトを実行して”MSBuild C:\Development\CustomTask\CustomTask.xml”のように打ち込んで実行すると下のようになる。
画面にHello Worldと表示されているのが確認できる。この例ではConsole.WriteLineを使ってコンソールに文字列を表示させたが、TaskクラスにはLogというクラスがプロパティとして存在していてそれを使ってコンソールに文字列を表示させたり、メッセージの重要度を指定してログすることも可能だ。
【MSBuildのプロパティ】
上で使用したMSBuild用のXMLファイルは言ってみればスクリプトである。MSBuildに何をどういう順序で実行していくかを記述している。MSBuildのファイルではプロパティを使用することができる。上の例で使用したLoggerクラスにLogFilePathという型がStringのプロパティを追加して、Executeメソッド内のコードを少し変えてみる。
Imports Microsoft.Build.Utilities Imports Microsoft.Build.Framework Public Class Logger Inherits Task Public Overrides Function Execute() As Boolean Log.LogMessage("LogFilePath = {0}", Me.LogFilePath) Return True End Function Private _LogFilePath As String <Required()> _ Public Property LogFilePath() As String Get Return _LogFilePath End Get Set(ByVal value As String) _LogFilePath = value End Set End Property End Class
LogFilePathというプロパティを追加してそれに<Required()>というAttributeを追加した。これを追加することによってこのプロパティは必ず値を持たなければMSBuildを実行したときにエラーが発生する。ではどうやってこのプロパティに値を渡してやるのだろうか。下のXMLを見ていただくとすぐに理解できるだろう。
<?xml version=”1.0″ encoding=”utf-8″ ?>
<Project xmlns=”http://schemas.microsoft.com/developer/msbuild/2003″>
<UsingTask AssemblyFile=”C:\Development\CustomTask\CustomTask\bin\Debug\CustomTask.dll” TaskName=”CustomTask.Logger”/>
<Target Name=”Jikkou”>
<Logger LogFilePath=”C:\Temp\Test.log” />
</Target>
</Project>
前と違うところは<Logger>タグ内にLogFilePathのAttributeが追加されたことだ。これによってLoggerクラスのLogFilePathプロパティに値を渡すことができるのだ。ではもうちょっと踏み込んでみよう。ビルドスクリプト(XML)が大規模になればなるほどプロパティを使用して値を変数として扱うことは十分に考えられて、またそれにしたがって複雑にもなってくる。そこで<PropertyGroup>を使うと変数の値が一元的に一箇所で取り扱うことができるから便利だ。下のXMLを見てみよう。
<?xml version=”1.0″ encoding=”utf-8″ ?>
<Project xmlns=”http://schemas.microsoft.com/developer/msbuild/2003″>
<UsingTask AssemblyFile=”C:\Development\CustomTask\CustomTask\bin\Debug\CustomTask.dll” TaskName=”CustomTask.Logger”/>
<PropertyGroup>
<HelloPath>C:\Temp\Test.log</HelloPath>
</PropertyGroup>
<Target Name=”Jikkou”>
<Logger LogFilePath=”$(HelloPath)” />
</Target>
</Project>
<Target>タグの前に<PropertyGroup>というタグを追加してその中に変数としてHelloPathを追加した。もちろん変数はいくつ追加しても可である。そしてHelloPathの値をLoggerのLogFilePathプロパティに$(HelloPath)として渡してやるのだ。さらに<HelloPath>の値をXMLファイル内に指定するのではなくてMSBuildを実行するときに渡してやりたい場合には・・・
MSBuild C:\Development\CustomTask\CustomTask.xml /p:HelloPath=”C:\Temp\Baka.log”
と/pスイッチを使用することによってすでにMSBuildスクリプト内にある値を変えることができる。
ここで触れたのはあくまでもカスタムな.NETのコードを実行する目的でMSBuildを紹介した。MSBuildは非常に深く、まだまだたくさんできることがある。MSBuild /?とコマンドラインに打ってやるといろいろなオプションがあるのが分かる。いろいろ試して遊んでみてほしい。
ふう・・・やっぱり技術ものを書くと長くなるなあ。
VS 2008と同時にリリースされた.NET Framework 3.5に含まれるWindows Presentation Foundation。実は会社の新しいプロジェクトでそのプロトタイプを作成するのにこれを使う予定だ。初めはよく分からなかったがChris AndersonさんのEssential Windows Presentation Foundationを読みながらやっていくとだんだんと分かってきた。面白い。やばい・・・PowerShellのようにはまりそうだ。
時間があったらこれについてもスクリーンキャストをやってみようか・・・
WordPressというブログソフトは知ってはいたがつい最近まで時間を割いていじってみることがなかった。先週の水曜日に仕事が終わってからいじる機会がありその高機能さに驚かされた。新しいブログソフトを使うとしても今まで書いてきた投稿を移行することは絶対条件として調べてみるとWordPressにはXML RPCという機能があり、VB .NETやC#からでもデータのやり取りができるのだ。それによってWindows Live Writerからのブログの編集や投稿が可能になっているのは言うまでもない。これによってブログ移行計画が自分の中で大きく前進した。
まず始めにやったのはDasBlogのデータをどうやって読み込むかが始めの問題だった。DasBlogはデータベースを使わずXMLのファイルを使ったブログエンジンである。このソフトはオープンソースなので読み込む方法は簡単に解決できた。ソースコードをダウンロードしてnewtelligence.DasBlog.Runtimeとnewtelligence.DasBlog.Runtime.Proxiesとnewtelligence.DasBlog.Utilのプロジェクトを参照して次ぎようにするとすべての投稿を読み込むことができる。
Dim rootPath As String = "D:\Backup\11-15-2007\content"
Dim dataService As IBlogDataService = BlogDataServiceFactory.GetService(rootPath, Nothing)
Dim entries As EntryCollection = dataService.GetEntriesForDay(DateTime.MaxValue.AddDays(-2), _
System.TimeZone.CurrentTimeZone, _
String.Empty, _
Integer.MaxValue, _
Integer.MaxValue, _
String.Empty)
entriesをループすることによって一つ一つの投稿を読み込むことができるのだ。
次の問題はどうやって.NETからXML RPCへアクセスするかだ。ウェブサービスとは違ってWSDLがないのでXSD.exeでプロキシクラスを生成することができない。いろいろ検索した末に行き着いたのが、XML RPC .NETだ。これはウェブサーバとの「生な」HTTP通信を包み込んでくれるコンポーネントなのだ。どうやって使うかというとサーバ側でサポートされているメソッドを下のようにプロキシ化する。
Imports CookComputing.XmlRpc
Public Interface IWordPressProxy
Inherits IXmlRpcProxy
<XmlRpcMethod("wp.getCategories")> _
Function getCategories(ByVal blog_id As Integer, ByVal username As String, _ ByVal password As String) As Category()
(中略)
End Interface
Interfaceは直接インスタンス化はできないのでXML RPCのコンポーネントを使ってインスタンス化し、各メソッドを使う。MetaWeblogのXML RPCへアクセスするコードはマイクロソフトのウェブサイトに載っていたので拝借した。UIを書くのは面倒だったらのですべてNUnitのコードで済ませた。あまり詳しく書くとすごく長くなってしまいそう(すでに長いけど)なので、このブログにそのコンポーネントを添付しておくことにしよう。
次に苦労したのはスキンの日本語化だ。元のスキンはSriniさんという人が作ったものだ。管理画面や基本的な部分はja.moのリソースファイルをダウンロードしてWordPressに読み込ませることで簡単にできることは先日の投稿で紹介した。しかし細かいところはすべてスキンのファイルに書き込まれているのでそれを手作業で日本語化してやる必要がある。WordPress上では日本語はUTF-8として扱われるので秀丸を使って編集するときにエンコードを変換し、日本語化していくのだ。日本語化するのにも一応コードを読んでそれを理解したうえで日本語化していかないとコンテクストを無視した日本語になってしまうので注意が必要だ。それでも変な日本語があったら教えて欲しい。元のスキンは自分が作ったものではないので日本語化したものをダウンロードを可能にするのは控えておくがもし欲しい人があったらここにコメントしていただければ送らせていただく。
てなわけでとりあえずブログの移行と日本語化が完了した。後はvbaspcoder.comのDNS設定を変えてこのブログに飛ばすようにするのみだ。404.phpを工夫しなきゃなあ・・・
VS2008インストールした後でちょっと見てみたら3.5ってASP .NETのアップグレードは含まないのね。%windir%\Microsoft.NET\Framework\v3.5にはaspnet_regiis.exeが入ってないしIISあけても1.1か2.0しか選択できない。
っていうことは今度の3.5って3.0と同じぐらいの位置づけか?でもVS2008リリースしているし結構大きなリリースだよなあ。開発者としては理解できるけどそうじゃない人に説明するの結構面倒なんだよな。「.NET Framework 3.5ってASP .NETは.NET Framework 2.0に対して実行されるんです。」なんて言うと頭の周りにクエスチョンマークがパッパッパッパッパッって現れるのが見えそう。
こんなんで簡単にBase64の暗号化ができてしまう。素人目にはいいでしょうが、すぐに解読されてしまいますがね。
class Base64
{
public string Encode(string text)
{
byte[] buff = System.Text.Encoding.UTF8.GetBytes(text);
return Convert.ToBase64String(buff);
}
public string Decode(string text)
{
byte[] buff = Convert.FromBase64String(text);
return System.Text.Encoding.UTF8.GetString(buff);
}
}
WPFには結構興味がある。もしかしてウェブ2.0をまた違った意味で変えてしまうのではないかと結構期待してるところがあるのだ。いってみればFlashを超えた存在になっていくのではないかという気がする。WPF/Eも他のプラットフォームもサポートするようだし・・・面白い展開である。
さてWPFのアーキテクチャについてちょこっと読んでいた。下の画像はそのMSDNの記事からの抜粋である。
milcoreとPresentaiton Coreという層がある。今までのUIに比べて3つの層が追加されたという感じだ。「すべてのコンピュータ科学における問題はアプリケーションレイヤーを追加することによって解決する」というのを聞いたことがあるが、WPFもその通りということであろうか。このWPFで期待したいのはGPUの性能を最大限に引き出せるように設計されているところだ。開発者としてはそういうところも念頭に置きながら開発していかなければいけないだろう。