ヒマをみつけてWeb開発
その場の思い付きを、ヒマをみつけてWebサイトにしてみるブログ

Cassandraemon 0.6.0をリリースしました( ̄∇  ̄ )

Saturday, 12 June 2010 11:17 by sabro

自分のプロジェクトへ組み込んで、地味に検証を続けていたCassandraemonですが、先程、バージョン0.6.0をリリースしました。一応ベータ版扱いにしてありますが、バグはだいたい潰し終わったと思います。

Cassandraemon 0.6.0

ドキュメントも頑張って英語で書いてみました。日本語版のドキュメントは今のところありませんが、リクエストがあったらどこかに作ります。

リリースノートにも書いてありますが、Cassandraemonで出来ることの一覧を挙げておきます。

  • LINQクエリでCassandraデータの取得が可能
  • Cassandraへの、登録、削除操作もサポート
  • 使い易い拡張メソッドがたくさん
  • 変態的なConvertメソッドで、Cassandra ByteデータからObjectへ楽々変換
  • TimeUUIDサポート
  • Javaとの相互運用性を考慮して、Big Endian形式でデータ登録

現状の.NETクライアントの中では結構イイ線いってるような気がします。っていうか、LINQで動くCassandraクライアントでまともなやつがないですからねえ。

Cassandraemonのバージョンは、本家Cassandraと連動しています。0.6.0を試すときは、Cassandraも0.6系を使ってください。Cassandraはまだまだ変化が激しいので、多分0.7になったら動かないと思います。Cassandraコミュニティの活発さを見ると、0.7もすぐにリリースされそうなので、はやくも追従していく必要がありそうです( ̄□  ̄ ||

それとは別に、Cassandraemon独自の機能追加も考えています。具体的に上げると

  • コネクションプーリング、ロードバランシング
  • リフレクションによるマッピングを、高速マッパーライブラリで速度改善
  • 全文検索機能

などです。

結構異質なのが、全文検索機能ですが、うちのプロジェクト「クリエモン」では、今までToritonnを使った全文検索を実装していたので、Cassandraへ移行するに当たって、そこを何とかしないといけないわけです。Lucandraとかもあるけど、複数のライブラリを使いまわすのもメンドくさそうですし、開発することにしました。さぶろーは全文検索とかほとんど知らないので、仕組みとしては簡単な物になると思います。

とりあえず報告はこんなところです。それでは、充実したカサンドライフ(セカンドライフみたいだ・・・)をお過しください( ̄∇  ̄ )

Tags:   , ,
Categories:   .NET | NoSQL
Actions:   Permalink | Comments (72) | Comment RSSRSS comment feed

Javaと.NETのエンディアンの違いでCassandraの互換性崩壊( ̄□  ̄ ||

Friday, 4 June 2010 02:23 by sabro

昨日の件ですが、Javaと.NETでは、数値をバイト配列にした際の順序はやはり逆になるようです。バイト配列の格納方式はエンディアンといって、先頭から素直に並べるビッグエンディアンと、逆順に並べるリトルエンディアンがあります。

Javaの場合は常にビッグエンディアンとなり、.NETの場合は、CPUによって並べ方が変わるようです。x86系のCPUでは、リトルエンディアンになるみたいですね。.NETでは、BitConverterクラスに、IsLittleEndianというフィールドがあるので、それを見て、自前でバイト配列を並べ替えることで対処は出来るみたいです。

で、Cassandraemonで数値を格納するときにどうするか決めないといけないわけです。少なくともLongTypeのカラム名に格納する際は、ソートできるようにビッグエンディアンへの変換が必要ですね。他の場合はどうするか・・・。Thrift側でやってくれたらよかったんだが。

1、すべての数値を格納前にビッグエンディアンへ変換する

とりあえず、数値をToCassandraByte関数などでバイトへ変換するときは、常にビッグエンディアンにしてしまうというやり方がまず考えられます。このやり方だと、カラム名だけでなくカラムの値もビッグエンディアンになります。この方式のいいところは、Javaと相互運用が可能な点です。常にビッグエンディアンが格納されるので、Javaからも問題なく読みだすことができるはず。ただ、完全ではなく、数値を自前で野良バイト変換してCassandraへ格納した場合に、整合性が取れなくなることはありますね。

2、LongTypeのカラム名に格納するときだけビッグエンディアンへ変換

Cassandraemon側で、LongTypeのカラム名登録の場合だけ、自動でバイト配列を逆順にするやり方です。.NETから見た場合の相互運用性が高くなります。他の.NETクライアント、例えばhectorsharpなどから、カラム名以外は違和感なく値の取得ができると思います(そういえば、hectorsharpでは、この問題どうしてんだろ)。

3、自動的な変換はやらない

Cassandraemon側では一切変更を行わず、リトルエンディアン変換関数とかを用意しておき、LongTypeカラム名登録時は各開発者に自分で変換を行ってもらうやり方です。面倒ではありますが、どのカラムにどのエンディアンで格納されているかを開発者側が管理出来ると言うメリットがあります。ただ、値取得時に、このカラムはどのエンディアンかを意識して変換する必要もあるので、大人数での開発などでは混乱も起こるかもしれません。

以上、やり方考えてみましたが、どれにしようかなあ( ̄□  ̄ ) 個人的には1か3を考えてますが、みなさん希望とかありますでしょうか( ̄∇  ̄ )

Tags:   , , , ,
Categories:   .NET | Java
Actions:   Permalink | Comments (58) | Comment RSSRSS comment feed

Cassandraでカラム名に数値を格納するときBytesType指定は可能か?

Thursday, 3 June 2010 10:24 by sabro

追記: 以下の文章では、結局BytesTypeではうまく取得出来ないから、LongTypeを使いましょうということが書いてありますが、LongTypeでもうまく取得出来ないようです。Cassandraemonのバグの可能性もあるので、詳しく調べ中です。

追追記: 試しにJassandraで、.NETからLongTypeに登録した値を取ってみたら、なぜか「72057594037927936」みたいな値が取れました。これを16進数に変換してみると、なんと「100000000000000」。もしかして、1で登録したやつが逆になってる・・・( ̄□  ̄ || とてつもなくイヤな予感がします。

追追追記: .NETでの登録時に、Reverse関数でバイト配列を逆順にしてやると、なんか想定通りの動きをしました・・・。あれ、ほんとにJavaと.NETって、数値から作ったバイト配列が逆順になるってことでしょうか( ̄□  ̄ || 詳しい方カモン!

追追追追記: 調べてみました。→ 次のエントリへ

Cassandraでは、カラム名の比較方法として、以下の6つが選べます。(本家サイトより引用)

  • BytesType: Simple sort by byte value. No validation is performed.
  • AsciiType: Like BytesType, but validates that the input can be parsed as US-ASCII.
  • UTF8Type: A string encoded as UTF8
  • LongType: A 64bit long
  • LexicalUUIDType: A 128bit UUID, compared lexically (by byte value)
  • TimeUUIDType: a 128bit version 1 UUID, compared by timestamp

カラム名に数値を入れたいときは、普通はLongTypeを使うのですが、今日、LongTypeのカラムに4バイトのint型を突っ込んだら、8バイトじゃないとダメよってエラーがでました( ̄□  ̄ || まあ、普通に対処するなら、バイト変換する前にLong型にキャストしてやればいいんですが、数値を格納する際に毎回キャストするのも面倒なので、比較タイプをBytesTypeにすることでキャストしなくてもいい具合に動いてくれないかどうか調べてみました。

BytesTypeの動作は、「org.apache.cassandra.db.marshal.BytesTypeクラス」で規定されてるようです。

public class BytesType extends AbstractType
{
    public int compare(byte[] o1, byte[] o2)
    {
        return FBUtilities.compareByteArrays(o1, o2);
    }

    public String getString(byte[] bytes)
    {
        return FBUtilities.bytesToHex(bytes);
    }
}

FBUtilitiesクラスっていうのを使ってるみたいですね。「org.apache.cassandra.utils.FBUtilitiesクラス」のようです。

public static int compareByteArrays(byte[] bytes1, byte[] bytes2){
    if(null == bytes1){
        if(null == bytes2) return 0;
        else return -1;
    }
    if(null == bytes2) return 1;

    int minLength = Math.min(bytes1.length, bytes2.length);
    for(int i = 0; i < minLength; i++)
    {
        if(bytes1[i] == bytes2[i])
            continue;
        // compare non-equal bytes as unsigned
        return (bytes1[i] & 0xFF) < (bytes2[i] & 0xFF) ? -1 : 1;
    }
    if(bytes1.length == bytes2.length) return 0;
    else return (bytes1.length < bytes2.length)? -1 : 1;
}

むう、先頭から順番に、どちらかの配列の終わりに達するまで比較して、それでも同じだったら、配列長の長い方が勝ちとなるようです。

次に、.NETで、BitConverterを使って、バイト配列に変換したとき、どんな感じに格納されるのか知らなかったので、実験してみました。

static void Main(string[] args)
{
	uint u1 = 10;
	uint u2 = 257;
	long l1 = 10;
	long l2 = 257;

	var bu1 = BitConverter.GetBytes(u1);
	var bu2 = BitConverter.GetBytes(u2);
	var bl1 = BitConverter.GetBytes(l1);
	var bl2 = BitConverter.GetBytes(l2);

	Console.WriteLine(bu1[0] + " " + bu1[1] + " " + bu1[2] + " " + bu1[3]);
	Console.WriteLine(bu2[0] + " " + bu2[1] + " " + bu2[2] + " " + bu2[3]);
	Console.WriteLine(bl1[0] + " " + bl1[1] + " " + bl1[2] + " " + bl1[3] + " " + bl1[4] + " " + bl1[5] + " " + bl1[6] + " " + bl1[7]);
	Console.WriteLine(bl2[0] + " " + bl2[1] + " " + bl2[2] + " " + bl2[3] + " " + bl2[4] + " " + bl2[5] + " " + bl2[6] + " " + bl2[7]);
}


/*
結果
10 0 0 0
1 1 0 0
10 0 0 0 0 0 0 0
1 1 0 0 0 0 0 0
*/

どうやら、バイト配列の先頭から格納されていくようです。しかし、256単位で繰り上がるので、10を変換した場合と、257を変換した場合では、バイト配列の1つめは、前者の方がおおきくなっていますね。これだと、多分、BytesTypeの比較では上手くいかない気がします。

ためしに実験。設定ファイルを以下のように定義。

<ColumnFamily Name="BytesType" CompareWith="BytesType" />

以下がテストコード。Cassandraemonを使っています。分かりにくいかもしれないですが、通常のThriftインターフェースを使うと、とんでもなく長くなりそうだったので・・・。

public static void Main (string[] args)
{
	using(var context = new CassandraContext("localhost", 9160, "Test"))
	{
		// 1, 10, 257 の、3カラムを生成
		var list = new List<Column>();
		list.Add(1, "")
			.Add(10, "")
			.Add(257, "");
			
		// 登録用エンティティ作成
		var entity = new CassandraEntity<List<Column>>()
				.SetColumnFamily("BytesType")
				.SetKey("hoge")
				.SetData(list);
				
		// 登録
		context.ColumnList.InsertOnSubmit(entity);
		context.SubmitChanges();
		
		// 1以上のデータを取得
		var q1 = from x in context.ColumnList
				 where x.ColumnFamily == "BytesType" &&
					   x.Key == "hoge" &&
					   x.Column.GreaterThanOrEqual(1)
				 select x;
				 
		Console.Write("条件 1以上 ");
		foreach(var e in q1)
		{
			foreach(var column in e.Data)
			{
				Console.Write(column.Name.ToInt32() + " ");
			}
			Console.WriteLine();
		}
		
		// 9以上のデータを取得
		var q2 = from x in context.ColumnList
				 where x.ColumnFamily == "BytesType" &&
					   x.Key == "hoge" &&
					   x.Column.GreaterThanOrEqual(9)
				 select x;
				 
		Console.Write("条件 9以上 ");
		foreach(var e in q2)
		{
			foreach(var column in e.Data)
			{
				Console.Write(column.Name.ToInt32() + " ");
			}
			Console.WriteLine();
		}
	}
}


/*
条件 1以上 1 257 10 
条件 9以上 10 
*/

9以上の値を取得しようとしてるのに、257が取れてこないですね。検証は正しかったようです。

というわけで、数値タイプをカラム名にするときは、素直にLongTypeを使いましょうということですね( ̄∇  ̄ ) で、格納するときは毎回ちゃんとlongにキャストするか、そもそもModelクラスのフィールドには基本的に、long型を使うようにするのがいいと思います(あくまで.NETの場合)。

Tags:   , ,
Categories:   .NET | NoSQL
Actions:   Permalink | Comments (58) | Comment RSSRSS comment feed

Zookeeperを.NETから使ってみる

Thursday, 13 May 2010 15:11 by sabro

Cassandraemonの正式版はもう少しお待ちを。実際にうちのサービスに組み込んでみて、安定して動くことを確認してからリリースします。

で、今組み込み作業中なんですが、CassandraだとMySQLでやってた連番生成が出来ないことに気づきました。Diggは、ZooKeeperを使ってやってるみたいです。TwitterはMySQLなのかな。

Zookeeperは、分散システムを協調動作させるために、Hadoopチームによって作られたライブラリです。データ構造は、ファイルシステムのようなツリー構造になっていて、それぞれのノードに対して、アトミックで順序保証されたアクセスが可能とのこと。

でも、Zookeeperは今のところ正式なものとしては、Java、C言語しかインターフェースが用意されていません。一応Http Restでの呼び出しでZookeeperにアクセスできる実験的機能があるみたいですが、これはWatcherがJavascriptからしか使えないとか制限があるみたいですね。

これは諦めるしかないかなと思ってたんですが、調べてみると本家ZookeeperをForkして、.NETドライバを作ってる方がいました!

http://github.com/ewhauser/zookeeper

最終更新日が5月4日。まだ作ってる最中かもしれないですね。本家にマージされたりしないのかな( ̄∇  ̄ )

Gitでソース取ってきて、MonoDevelopで開いたところ、いくつかソースが足りません。どうやら、Antでソースを作る必要があるみたいなので、トップディレクトリでAnt実行。すると、無事ソースコードが作られてビルド成功しました(^^)

それでは、せっかくなんでC#で接続してみます。Zookeeperのインスタンスを作るには、IWatcherインターフェースを実装したクラスを自作しないといけないみたいなんで、適当にでっちあげます。(追記:Watcherが不要なら、Nullを渡してもいいみたいです)

public class DefaultWatcher : IWatcher
{
	public void Process (WatchedEvent @event)
	{
		Console.WriteLine(@event.Path);
		Console.WriteLine(@event.Type);
		Console.WriteLine(@event.State);
	}
}

最初は、ZNodeを作る例です。Zookeeperのコンストラクタには、接続ホスト名&ポート、セッションタイムアウト、でっちあげたWatcherを渡します。Createメソッドでは、ノードパス、格納データ、接続ACL、CreateModeを渡してます。接続ACLはいくつか定数で用意されてたので、そのまま使いました( ̄∇  ̄ )

using(var zookeeper = new ZooKeeper("RemoteLinuxServer:2181", 
                                    new TimeSpan(0,1,0), 
                                    new DefaultWatcher()))
{
	var response = zookeeper.Create("/node1", 
	                                Encoding.UTF8.GetBytes("data1"), 
	                                Ids.OPEN_ACL_UNSAFE,
	                                CreateMode.Persistent);
	                                

	Console.WriteLine("Create : " + response);
}

// ### result ###
// Create : /node1

接続先のLinuxサーバ側で確認してみると、ルートディレクトリに「node1」が作られていました。今度は、Linuxサーバ側で、node2を作ってみます。

[root@RemoteLinuxServer bin]# ./zkCli.sh -server 127.0.0.1:2181
[zk: 127.0.0.1:2181(CONNECTED) 1] ls /
[node1, zookeeper]
[zk: 127.0.0.1:2181(CONNECTED) 2] create /node2 data2
Created /node2

再び、C#に戻って、GetChildrenメソッドにパスと、Watchフラグを渡して実行。Linuxサーバ側で追加したnode2が取れてます。

using(var zookeeper = new ZooKeeper("RemoteLinuxServer:2181", 
                                    new TimeSpan(0,1,0), 
                                    new DefaultWatcher()))
{
	var responses = zookeeper.GetChildren("/", false);

	foreach(var res in responses)
	{
		Console.WriteLine("GetChildren : " + res);
	}
}

// ### result ###
// GetChildren : node2
// GetChildren : node1
// GetChildren : zookeeper

うーん、グッジョブと言わざるをえない。とりあえず、もうちょっといじってみたいと思います( ̄∇  ̄ )

Tags:   ,
Categories:   .NET | NoSQL
Actions:   Permalink | Comments (46) | Comment RSSRSS comment feed

DateTime.Ticksの精度は100ナノ秒ではない

Thursday, 6 May 2010 07:41 by sabro

DateTime.Ticksプロパティの説明には

「このプロパティの値は、0001 年 1 月 1 日午前 00:00:00 (DateTime.MinValue を表します) 以降の経過時間 (100 ナノ秒単位) を表します。」

って書いてあります。でも、これは桁数がそれだけ用意してありますよっていうだけで、実際は、動作OSによって精度が異なるみたいです。

ちょっとうちのVistaで実験

static void Main(string[] args)
{
	for (int i = 0; i < 100; i++)
	{
		Console.WriteLine(DateTime.Now.Ticks);
	}
}

こんなかんじで実行したところ、結果は以下のような感じでした。

634086940404282076
634086940404312076
634086940404312076
634086940404312076
634086940404312076
634086940404312076
634086940404312076
634086940404312076
634086940404312076
634086940404312076
634086940404312076
634086940404312076
634086940404312076
634086940404312076
634086940404312076
634086940404312076
634086940404322076
634086940404322076
634086940404322076
634086940404322076
634086940404322076
634086940404322076
634086940404322076
634086940404322076
634086940404322076
:
:

下4桁は固定で、1ミリ秒単位で増加するようです。うっかりMSDNの内容をうのみにしないように気をつけないといけませんね。

こっから蛇足。

なんで、こんな実験したかっていうと、作成中のCassandra LINQプロバイダ、Cassandraemonで、TimeUUIDをキーにする必要があったからなんです。TimeUUIDは、現在の100ナノ秒単位のタイムスタンプから生成されるIDのようなもので、かなりの確率で複数マシン間で一意になることになってます。

ところが、これをDateTime.Ticksから生成すると、1ミリ秒単位なので結構な確率で同じものが生成されてしまうんですね。これでは、テーブルのキーとして使うには厳しいわけです。

うーん、内部でミリ秒以下は適当に生成するとかで凌ぐしかないのかなあ。なんかいいアイデアないでしょうか( ̄∇  ̄ )

Tags:   , , , ,
Categories:   .NET
Actions:   Permalink | Comments (43) | Comment RSSRSS comment feed

CassandraのLINQProvider作ったよ( ̄∇  ̄ )

Friday, 23 April 2010 21:03 by sabro

今をときめくCassandraの、LINQプロバイダを作ってみました( ̄∇  ̄ )

Cassandraemon in CodePlex
Cassandraemon

こんな感じで、データを取ってこれます。

public class Product
{
	public int ID { get; set; }
	public string Name { get; set; }
}

	
using(var context = new CassandraContext("localhost", 9160, "KeySpace1"))
{
	var products = from x in context.ColumnList
		       where x.Key == "1" &&
			     x.ColumnFamily == "Product"
		       select x.ToObject<product>();
				   
	foreach(var p in products)
	{
		Console.WriteLine(p.ID.ToString());
	}
}

一応、更新系もサポートしています。より詳しい解説はドキュメントページを見てください。

まだとりあえずクエリ、更新処理が動いたことを確認できただけの段階です。全く使い込んでないのでバグもあるかも。ある程度使ってみて安定してきたら、ちゃんと正式版用意すると思います。

今後の開発方針ですが、さぶろーはセカンドライフ系サービスの開発が忙しいため、Cassandraemonに関しては、積極的なコミットはしない予定です。本家のバージョンアップで追加されたAPIくらいには対応したいですけどね。

ソースコード管理はMercurialなので、機能追加されねーって場合は、自分でForkして作ってみるのも一興かもしれません。

ちなみに、プロジェクト名の由来は、セカンドライフで絶賛稼働中の、拙作、萌え系アバターサービス「クリエモン」からです。

クリエモン

今までクリエモンのバックグラウンドではMySQLを使っていたのですが、メンテナンスが大変なのと、NoSQL使ってみたかったという理由から、Cassandraに切り替えることにしました。クリエモンで使うCassandraドライバなので、Cassandraemonというわけです。某国民的アニメとは全く関係ないのでご注意ください( ̄∇  ̄ )

Tags:   , , , ,
Categories:   .NET | NoSQL
Actions:   Permalink | Comments (63) | Comment RSSRSS comment feed

BlogEngine.NET-1.6への移行手順

Friday, 19 March 2010 16:52 by sabro

BlogEngine.NETを、バージョン1.5から1.6へアップデートしました。さぶろーは、Mono On Linuxで動かしているので若干特殊ですが、移行手順を書いときます。

  1. App_Dataディレクトリをバックアップ
  2. App_Code内の、ExtensionManagerディレクトリを削除(今回から、BlogEngine.Coreへ移動したため不要になったそうです)
  3. 1.6の全ファイルを、1.5へ上書き
  4. App_Dataを1.5のバックアップで上書き
  5. App_Data/settings.xmlに設定項目が追加されたので、1.5で使っていたのものに以下の項目を追加
      <commentsperpage>20</commentsperpage>   <moderationtype>1</moderationtype>   <numberofreferrerdays>1</numberofreferrerdays>   <commentblacklistcount>2</commentblacklistcount>   <commentwhitelistcount>1</commentwhitelistcount>   <enableerrorlogging>False</enableerrorlogging>   <trustauthenticatedusers>True</trustauthenticatedusers>
  6. Web.Configで、System.Managementアセンブリを読み込んでいる部分をコメントアウト(Linuxのみ)
  7. Web.Configを、web.configへリネーム(Linuxのみ)
  8. BlogEngine.Web/admin/Comments/default.aspxを、Default.aspxへリネーム(Linuxのみ)

Linuxなんで、ファイルの大文字、小文字を気をつけないとアクセスできないんですね、う~ん微妙( ̄∇  ̄ )

Tags:   , ,
Categories:   .NET
Actions:   Permalink | Comments (53) | Comment RSSRSS comment feed

CentOS5.4で、mono2.6.1をソースからビルド

Thursday, 25 February 2010 19:29 by sabro

Linux Monoで、BlogEngine.NETを動かすで書いたとおり、Mono2.0以上では、うちのクリエモンが動かなかったのですが、やっぱり最近のバージョンの方がパフォーマンスも上がってるだろうし、もっかい試してみんべってことで、mono-2.6.1をソースからビルドしてみました。openSUSE向けならバイナリもあるみたいですが、さぶろーが使ってるCentOSでは、ソースから入れないとダメみたいです。

前提として、今回使用するマシンには、以前古いバージョンのMonoをソースから入れた気がするので、OSインストール直後のまっさらな状態だと、もっと依存ライブラリのエラーが出るかもしれません、注意。(たしか、画像関連のライブラリと、apacheの開発用パッケージが必要だった気がする)

さぶろーの場合、あくまでもWebサイトをホストするのが目的なので、簡易ASP.NETサーバのXSPと、ApacheのMonoモジュールであるmod_monoも入れることにします。あと、System.Drawing名前空間のクラスを使う場合は、libgdiplusも必要です。クリエモンは画像のアップロードで、該当クラスを使ってるので、こっちも入れます。

また、ソースからインストールすると削除するときなど手動では大変なので、ソースコードパッケージを管理できるPacoっていうツールを使います。make installするときに、次のようにかませて使います。 # paco -D make install

必要なパッケージをダウンロード
Mono 2.6.1 Sourcesからソースパッケージをダウンロード、解凍します。 さぶろーは、以下のパッケージをダウンロードしました。
  • libgdiplus-2.6
  • mono-2.6.1
  • xsp-2.6
  • mod_mono-2.6
libgdiplusをビルド
# cd libgdiplus-2.6 
# ./configure 
# make 
# paco -D make install 
monoをビルド
# cd mono-2.6.1 
# ./configure 
# make 
# paco -D make install 
xspをビルド
# cd xsp-2.6 
# ./configure 
# make 
と、ここまでやったところでエラーが( ̄□  ̄ ||
/usr/local/bin/mcs -pkg:dotnet -r:System.Xml.dll -target:library -out:SiteMapReader_1.1.dll SiteMapReader_1.1.cs Package dotnet was not found in the pkg-config search path. Perhaps you should add the directory containing `dotnet.pc' to the PKG_CONFIG_PATH environment variable No package 'dotnet' found error CS8027: Error running pkg-config. Check the above output.
メッセージの通りに、PKG_CONFIG_PATHを設定してあげたらうまくいきました( ̄∇  ̄ )
# export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
# make
# paco -D make install 
mod_monoをビルド
# cd mod_mono-2.6
# ./configure
# make
# paco -D make install

割とすんなり終了。やっぱ、前回入れたからかな。あんまり参考にならないエントリでした・・・。

Tags:  
Categories:   .NET
Actions:   Permalink | Comments (53) | Comment RSSRSS comment feed

開発環境をMonoDevelopへ移行しました

Sunday, 14 February 2010 12:30 by sabro

長いことVisualStudio使ってましたが、じつは去年の終わりくらいにMonoDevelopへ移行しました。MonoDevelopは、去年末に出したバージョン2.2から、Windowsを本格的にサポートしたみたいで、若干おかしい動きもありますが、開発に重大な支障なく使えてます。

移行したメインの理由は、Viモードがあるからです。VisualStudioでも有料のVimプラグインや、VimエディタからVisualStudioを操作するようなツールはあるんですが、MonoDevelopはIDEが最初からViのキー入力をサポートしており、メニューで設定をいじるだけでコードエディタでViキーバインドが使えるようになります。まだまだサポートしているキー自体は少ないですが、それでも作業効率が上がった気がします。もちろん、インテリセンスもちゃんと使えますよ( ̄∇  ̄ )

さて、お目当てはViモードだったんですが、他にもいくつか良い点がありました。

1つ目は、C#の最新の構文が使えるようになったことです。じつは、さぶろーは、VisualStudio2005を使っていました。、MonoRailが正式にVS2008をサポートしてないという話だったからです。たぶん2008でも開発は出来るだろうと思うんですけど、大事をとって2005にしていたのでした。2005は、C#2.0までしかサポートしないんで、ラムダ式、LINQ、型推論、拡張メソッドなどの便利な機能が使えません>< MonoDevelop2.2は、C#3.0をサポートしているほか、一部C#4.0をサポートしているそうです ←(これはMonoの話でMonoDevelopは関係なかったかも)。今ではラムダ式使いまくりです(^^)

2つ目は、フリーでありながらExpressEditionの制約がないことです。MonorailをVS2005 ExpressEditionで開発する方法まとめで書いたとおり、ExpressEditionではVSC#とVSWDを切り替えつつ開発していく必要があり、プロジェクト構成も汚くなりがち。MonoDevelopでは、VSのStandardEdition以上と同じく、1つのIDEでクラスライブラリも、ASP.NETプロジェクトも同一のソリューション上で開発できます。

3つ目は、Monoで動かない機能は、そもそも作れないようになっていることです。VisualStudioで作って、Linux上のMonoVMで動かそうとすると、Monoでは動作しないような場合があるんですが、MonoDevelopはMonoと足並みを揃えて開発されているので、そのようなことがありません。MonoVMで動かしたいという方は、検証が楽になると思います。

もちろん、良い点だけではなく、不満点もいくつかありました。

  • MonorailのViewEngineの1つ、AspView用のaspxファイルでで開けないものがある
  • デバッグ時に、変数の値がなかなか表示されないことがある

 

aspxが開けなかった問題は少し面倒でしたが、別途テキストエディタで開いて編集しています。

最後に、移行時に行なった作業ですが、MonoDevelopはVisualStudioのプロジェクトをそのまま開くことが出来るので、基本的には作業不要でした。ただ、日本語は文字化けしたので、Shift-JISから、UTF-8への変換だけ行ないました。

さぶろーは、かなりMonoDevelop気に入ってしまいましたが、みなさんどう感じましたでしょうか。MonoVM上でプログラムを動かしたい方にはオススメです( ̄∇  ̄ )

Tags:   , , ,
Categories:   .NET
Actions:   Permalink | Comments (45) | Comment RSSRSS comment feed

CGIのURLエンコードと、JavascriptのURLエンコードは微妙に違う

Wednesday, 22 July 2009 07:48 by sabro

クリエモンでURLエンコード周りのバグを出してしまいました( ̄□  ̄ ||

原因はCGIとJavascriptでURLエンコードが微妙に違うことでした。WikipediaのURLエンコードのページをみると、Javascriptでは、スペースは「%20」にエンコードされるが、CGI側では普通は「+」に変換されると書いてあります。なんでそんなややこしいことになってんだろ。これって知らないの僕だけで他のWeb開発者の間では常識なのかな(_ _ ||

とりあえず、おかしくなっていた部分では、HttpUtilityクラスのUrlEncodeメソッドが使われていました。以下はPowerShellでちょっと確認してみたところ。HttpUtilityクラスは、そのままでは参照できないんでリフレクションで「System.Web.dll」を読み込んでいます。


PS C:> [System.Reflection.Assembly]::LoadWithPartialName("System.Web")

GAC    Version        Location
---    -------        --------
True   v2.0.50727     C:\Windows\assembly\GAC_32\System.Web\2.0.0.0__b03f5f7f11d50a3a\System.Web.dll

PS C:> [System.Web.HttpUtility]::UrlEncode("<hoge fuga>")
%3choge+fuga%3e


PowerShell覚えると、インタプリタで動作確認ができちゃって楽ちんだな~( ̄∇ ̄) で、結果を見ると確かに「+」にエンコードされていますね。

調べてみると、UriクラスのEscapeDataStringメソッドを使えばJavascript形式のエンコードが出来るらしいとのこと。どれどれ


PS C:> [Uri]::EscapeDataString("<hoge fuga>")
%3Choge%20fuga%3E


おお、たしかに「%20」にエンコードされました(^^) 結局、UrlEncodeメソッドを使用している箇所を、のきなみEscapeDataStringメソッドに置き換えて、問題は解決したのでした。

ちなみに、UriクラスにはEscapeUriStringというメソッドもあります。こちらがどんな動作をするのか気になったので、サクッと確認してみました。


PS C:> [Uri]::EscapeDataString("http://www.hogefuga.com/<hoge fuga>")
http%3A%2F%2Fwww.hogefuga.com%2F%3Choge%20fuga%3E

PS C:> [Uri]::EscapeUriString("http://www.hogefuga.com/<hoge fuga>")
http://www.hogefuga.com/%3Choge%20fuga%3E


EscapeDataStringメソッドは、URLのコロンやスラッシュもエンコードしてしまいますが、EscapeUriStringメソッドは、URLを構成するための記号はエンコードしていません。すでに、URLになっている文字列に対してエンコードしたい時はこちらを使えばいいわけですね( ̄∇  ̄ )

Tags:   , , ,
Categories:   .NET
Actions:   Permalink | Comments (48) | Comment RSSRSS comment feed