System.Net.WebClient
あーあー。
そうでした、MonoのWebClientはGetWebRequestメソッドをオーバーライドできないのでした…。
以前にもやってハマったのでした。うーん。
TwitterIrcGateway on Mac OS X + Mono 1.2.4
なかなか暇が無くて触れないのですが、1.2.4で動いたという話を聞いたのでバイナリ入れて試したら確かに動くようになってました。
おー。すばらしす。
まあTIGはどうでも良くて、Cocoa#とかを試したいのです。Objective-Cも触らないと……。
Re: mkbundle --machine-configが2.0のconfigで機能しない件
id:atsushieno:20070417:p1
ありがとうございます。あげていただいたdll入れ替えで試してみたのですがどうもやはり読まれてない雰囲気でした。
それでソースにパッチを当てて自分で調べようと思いつつ、チェックアウトしてたら寝てたり(謎)、他の事をやったりで数日がたち追えておりません。すみません。
[Mono] mkbundle
まあ --deps --static --machine-config で実行してごっそり固めるところまでは簡単で、そのままそのマシン上であれば動きます。
ですがほかのマシンに持ってゆくといい感じで動いてくれません。
たとえばWebRequest.Createの内部のGetCreatorでprefixに対応するIWebRequestCreateを取得できなかったり、そこを無理やり登録してもGetResponseメソッドの中でリクエストを送信する際以下のような感じで死んでみたり。
Unhandled Exception: System.TypeInitializationException: An exception was thrown by the type initializer for System.Net.ServicePointManager ---> System.InvalidCastException: Cannot cast from source type to destination type. at System.Net.ServicePointManager..cctor () [0x00000] --- End of inner exception stack trace ---
行数が出ていないのでアレなのですが
static ServicePointManager () { #if NET_2_0 && CONFIGURATION_DEP object cfg = ConfigurationManager.GetSection (configKey); ConnectionManagementSection s = cfg as ConnectionManagementSection; if (s != null) { manager = new ConnectionManagementData (null); foreach (ConnectionManagementElement e in s.ConnectionManagement) manager.Add (e.Address, e.MaxConnection); return; } #endif manager = (ConnectionManagementData) ConfigurationSettings.GetConfig (configKey); }
の最後の行で落ちてるようですね。これはWebRequest.GetCreatorとも同じでConfigurationManager.GetSectionが空っぽになっているせい(なのでWebRequestはprefixが何も登録されていない)。
試しに
using System; using System.Reflection; using System.Configuration; using System.Net.Configuration; using System.IO; class Test { public static void Main(String[] args) { Console.WriteLine(ConfigurationManager.GetSection("system.net/connectionManagement")); object cfg = ConfigurationManager.GetSection ("system.net/connectionManagement"); ConnectionManagementSection s = cfg as ConnectionManagementSection; if (s != null) { //manager = new ConnectionManagementData (null); foreach (ConnectionManagementElement e in s.ConnectionManagement) Console.WriteLine ("{0} / {1}", e.Address, e.MaxConnection); return; } } }
というのを実行してもbundleしたものを持っていった先では何もでません。
で、さっきのコンストラクタの例だとそのままreturnにたどり着かないで最後の行にたどり着いて、GetConfig で ConnectionManagementSection が帰ってきて死亡。
ということはmachine.configが読み込まれてないんじゃ?と思って、どういう風になっているのかと思ったのですが
- bundleのCソース
- mono/mono/metadata/mono-config.c 511:mono_register_machine_config (const char *config_xml)
- mono/mono/metadata/mono-config.c 517:mono_get_machine_config (void)
- mono/mono/metadata/icall.c 6055: ves_icall_System_Configuration_DefaultConfig_get_bundled_machine_config (void)
- mcs/class/System/System.Configuration/ConfigurationSettings.cs 205: extern private static string get_bundled_machine_config ();
- mcs/class/System/System.Configuration/ConfigurationSettings.cs 206: internal static string GetBundledMachineConfig ()
- mcs/class/System/System.Configuration/ConfigurationSettings.cs 174: if (data.LoadString (GetBundledMachineConfig ())) {
らしいのでSystem.Configuration.DefaultConfig.GetBundledMachineConfig メソッドでちゃんと返ってくるかどうかみたのですが、一応中身は返ってきてる風。というかConfigurationSettings.GetConfig メソッドでは返ってきますし。
で、ConfigurationManager.GetSection を見てみるわけですが
http://anonsvn.mono-project.com/viewcvs/trunk/mcs/class/System.Configuration/System.Configuration/ConfigurationManager.cs?rev=62342&view=auto
http://anonsvn.mono-project.com/viewcvs/trunk/mcs/class/System.Configuration/System.Configuration/ClientConfigurationSystem.cs?rev=60483&view=auto
http://anonsvn.mono-project.com/viewcvs/trunk/mcs/class/System.Configuration/System.Configuration/InternalConfigurationFactory.cs?rev=46444&view=auto
まあ、System.Configuration.DefaultConfig.GetBundledMachineConfig が呼ばれていなさそうということはわかりました。
そういえばこういうinternalなコアライブラリをデバッグするときはデバッグコードを入れてビルドして、ということをやるのだとしてもビルドの時間とかライブラリの配置とかめんどくさそう……(よくわからないので内部を見たいときはActivatorとMethodInfoでがんばってた)。
そしてその場しのぎで無理やり解決する方法を思いついた
strace でファイルの位置を確認して、
$ mkdir -p mono/2.0/ $ cp machine.config mono/2.0/ $ export MONO_CFG_DIR=./ && ./test System.Net.Configuration.ConnectionManagementSection * / 2
ktkr!
ということはmkbundle2のオプションで --config-dir ./ とかやっておけばよさそうと思ったのでやってみたらだいじょぶっぽい。
おー。WebRequest.Createのprefixが登録されない問題もコレでクリア。根本的な解決にはなってないのですが。
[Mono] Mac OS XでWebRequestがアレなのは
bugzilla #81378にageていただきました。
わざわざありがとうございます。ぺこぺこ。
あきらめた。
ランタイムの中でしかもスレッドとなると手が出せないのであきらめ……。