老實說,這還真令人困擾,還好官方有說明如何得到更詳細的除錯資訊:Troubleshooting :: Castle Project。
基本上,就是加上一些設定,於是NHibernate 能根據這份設定以及內部有用到的 log4net library把一些訊息丟到 log 裡面去。
靠著產出出來的 log,終於找到問題。
樂透下期號碼預測(3)-完結
為甚麼沈寂了這麼久才寫這篇,那是因為我發現,樂透是不可預測的。其實有學過統計學的我早應該知道了。
如果你還是想試試看預測,那麼可以參考這一系列排列組合的文章,應該會很有幫助:
Porting guide
今天看到jpobst的這篇文章:Porting Guide。
他說,他上星期在Mono wiki上寫了一篇Guide: Porting Winforms Applications,內文提到如何將NClass移植到 Linux Mono 上的過程。
整個移植的過程相當簡單,首先利用MoMA (Mono Migration Analyzer)去分析NClass,得知NClass使用了哪些類別,而這些類別(內部的method)在Mono裡面是否已經被實做、有沒有使用 P/Invoke 等技術等等,接著再去補足Mono的類別或改寫 NClass(別忘記寄patch給原作者啊),這樣就完成整個移植的過程。
對於想把 Windows 上的 .Net 應用程式移植到 Linux 的人,這是一篇相當具有參考性的文章。
ActiveRecord
ActiveRecord是一套相當不錯的 Pattern library,主要是實做ActiveRecord pattern,底層則是NHibernate。
大致的原理主要是在 Entity class 的屬性上加上 Attribute,Pattern 再根據這些資訊與設定來作 Object-relation mapping。
官方網站提供了一份很簡潔的指引:Getting started with ActiveRecord
很簡單,也很清楚,但是如果你想要更深入了解一些的話,我建議不妨參考大陸網友Yuhen的這一系列文章:
- [ActiveRecord] 之一:初始化和配置 – Q.yuhen
- [ActiveRecord] 之二:常用方法 – Q.yuhen
- [ActiveRecord] 之三:SessionScope – Q.yuhen
- [Castle AR] 4. CRUD – Q.yuhen
- [Castle AR] 5. Base Relations – Q.yuhen
或是Oren Eini的系列文章:
- Castle Demo App: Getting Started With Active Record
- Castle Demo App: Active Record Relations
- Castle Demo App: Lazy Loading and Scopes
- Castle Demo App: Many To Many Relations
或是Hamilton Verissimo的系列文章:
- All you wanted to know about Castle ActiveRecord – Part I
- All you wanted to know about Castle ActiveRecord – Part II
我覺得都寫的相當不錯。
原本官方有提供很不錯的工具:ActiveRecord Generator,可以幫你從建好的 Database schema 去產生 entity class,省去你手動寫 code 的痛苦。
只是現在因為人力不足的關係,暫時停止繼續開發。
如果你想試試看所謂的ORM,不妨試試看這個 Library,可以讓你少寫掉很多很多 code。
tf4mono
原來早已經有非微軟官方釋出的 Team Foundation Server 的 client 端工具了~
這樣子不管是在 Linux 下或是在不想使用微軟官方 client 的情況下,都可以方便的去存取 CodePlex 的 Repository 了。
網址在這裡:tf4mono
目前只有提供 Console mode 的指令,作者希望未來可以提供 MonoDevelop 的 Add-In…
消息來源:
Visual WebGui (VWG)
今天在 Mono-dev 群組上看到有人詢問是否有類似 GWT 的軟體,可以快速開發 .Net 上的 ajax 程式。
Miguel 大大回答到有這麼一套:Visual WebGui (VWG)
有空的話,來試試看好不好用。
利用 Gmail SMTP server 來寄信
詳情可以參考這篇:Send E-Mail from your .NET application using your GMail Account,內文提供了 .Net 1.1/2.0 的方法。
我自己用 .Net 2,試的結果,發現有這個錯誤訊息出現:”Must issue a STARTTLS command first”
Google 大神告訴我,有蠻多人詢問這個問題。
仔細研讀之後,發現是我自己忘了幫 SmtpClient 設置 EnableSsl 屬性為 true。
加上之後,又丟出 “The requested feature is not implemented.”。
咦?沒實做,難道我用的Mono 1.2.3.1還沒實做這部份?
用Reflector反組譯出來看之後,果然…真的還沒實做 SSL 傳輸的部份。
希望下一版會加進去…這樣就可以在 Linux 下使用了。
以下是程式碼,它是一個命令列的程式,讓你可以指定必要的欄位後寄送郵件。
打 MailSharp -h 可以得到使用說明。
/** * MailSharp * * Reference: * Send E-Mail from your .NET application using your GMail Account - The Code Project - C# Programming <http://www.codeproject.com/useritems/SendMailUsingGmailAccount.asp> */ using System; using System.Text; using System.IO; using System.Net; using System.Net.Mail; using System.Net.Mime; using System.Threading; using System.ComponentModel; namespace MailSharp { public class MailSharpConsole { public static string showUsage() { StringBuilder sb = new StringBuilder(); sb.AppendLine( "Usage: MailSharp [options] ToAddress" ); sb.AppendLine( "\t-a File to attach." ); sb.AppendLine( "\t-f From address" ); sb.AppendLine( "\t-b Body message" ); sb.AppendLine( "\t-s Subject"); sb.AppendLine( "\t-S SMTP server host" ); sb.AppendLine( "\t-U Username for SMTP server authentication" ); sb.AppendLine( "\t-p Password for SMTP server authentication" ); sb.AppendLine( "\t-l Use SSL" ); sb.AppendLine( "\t-h Help/Usage"); sb.AppendLine(); sb.AppendLine( "Example:" ); sb.AppendLine( "\tFor GMail" ); sb.AppendLine( "\tMailSharp -f your_name@gmail.com -b Test -s Test -S smtp.gmail.com -P 587 -l -U your_gmail -p your_gmail_password someone@somewhere.com" ); return sb.ToString(); } public static void Main(string[] args) { MailAddress from = null; MailAddress to = null; MailMessage message = new MailMessage(); SmtpClient client = new SmtpClient(); NetworkCredential myCred = new NetworkCredential(); bool bShowUsage=false; try { if ( args.Length > 0 ) { for ( int i=0; i<args.Length; i++ ) { switch ( args[i] ) { case "-S": // server host i++; if ( i<args.Length ) { client.Host = args[i]; } else throw new Exception( "-S was specified, but no value." ); break; case "-P": // server port i++; if ( i<args.Length ) { client.Port=Convert.ToInt32( args[i] ); } else throw new Exception( "-P was specified, but no value." ); break; case "-T": // timeout i++; if ( i<args.Length ) { client.Timeout = Convert.ToInt32( args[i] ); } else throw new Exception( "-T was specified, but no value." ); break; case "-U": // username for smtp server authentication i++; if ( i<args.Length ) myCred.UserName = args[i]; else throw new Exception( "-U was specified, but no value." ); break; case "-p": // password for smtp server authentication i++; if ( i<args.Length ) myCred.Password = args[i]; else throw new Exception( "-p was specified, but no value." ); break; case "-l": // use SSL client.EnableSsl = true; break; case "-s": // subject i++; // next one is subject. if ( i<args.Length ) { message.Subject = args[i]; message.SubjectEncoding = System.Text.Encoding.UTF8; } else throw new Exception( "-s was specified, but no value." ); break; case "-a": // attachment i++; // next one is attachment filename. if ( i<args.Length ) { // Add attachment. Attachment data = new Attachment( args[i], MediaTypeNames.Application.Octet); message.Attachments.Add(data); } else throw new Exception( "-a was specified, but no value." ); break; case "-b": // body message. i++; // next one is body message if ( i<args.Length ) { message.Body = args[i]; message.BodyEncoding = System.Text.Encoding.UTF8; } else throw new Exception( "-b was specified, but no value." ); break; case "-f": // from address i++; if ( i<args.Length ) { // Specify the e-mail sender. // Create a mailing address that includes a UTF8 character // in the display name. // from = new MailAddress( "someone@gmail.com", "someone", System.Text.Encoding.UTF8); from = new MailAddress( args[i] ); } else throw new Exception( "-f was specified, but no value." ); break; case "-h": // show help/usage bShowUsage=true; break; default: to = new MailAddress( args[i] ); break; } } } else throw new Exception("No arguments."); } catch ( Exception ex ) { Console.WriteLine( ex.Message ); bShowUsage = true; } try { if ( bShowUsage == true ) throw new Exception( showUsage() ); if ( from==null ) throw new Exception( "Must specify from address (-f)." ); // Set destinations for the e-mail message. if ( to == null ) throw new Exception("At least, must specify to address"); if ( client.Host == string.Empty ) throw new Exception("Must specify SMTP Server (-S)." ); // Specify the message content. message.From = from; message.To.Add( to ); // Credentials are necessary if the server requires the client // to authenticate before it will send e-mail on the client's behalf. //client.UseDefaultCredentials = false; client.Credentials = myCred; // Send. // If you need asynchronous sample, please visit the reference above. client.Send(message); Console.WriteLine("Done."); } catch ( Exception ex ) { Console.WriteLine( "Exception was raised when sending..."); Console.WriteLine( ex.Message ); } finally { // Clean up. message.Dispose(); } } } }
如果你打算在 Linux 下服用的話,可以搭配這個 script,免去你每次前面都要打 mono 的麻煩。
#!/bin/sh exec /usr/bin/mono $MONO_OPTIONS "MailSharp.exe" "$@"
Mono Cecil
這篇文章:Using Cecil from IronPython再次勾起我去年初看到 Mono.Cecil 時的回憶。
什麼是Mono.Cecil??以下翻譯自Nauman Leghari’s Blog : Fun with IronPython and Cecil:
“Cecil 是由 Jb Evain (http://evain.net/blog/)所撰寫的類別庫,可以用來產生或注射自訂程序到以ECMA CIL撰寫的程序和類別庫。它提供了對泛型的完整支援以及對除錯資訊的部份支援。簡單的說好了,用了 Cecil,你可以載入已經存在的組件,瀏覽裡面所有的型別,即時修改它們並保存修改過的組件。”
看起來是個很神奇的東西吧~這兩篇文章介紹了如何以IronPython去使用Cecil,是很不錯的指引文章:
- Nauman Leghari’s Blog : Fun with IronPython and Cecil
- Nauman Leghari’s Blog : Fun with IronPython and Cecil (Part II)
此外也可以參考官方提供的Cecil FAQ。
如何存取SQLite
如果你還在找SQLite的 ADO.Net driver 的話,別找了。
因為Mono就提供了一個:SQLite at Mono。
不管你是在 Windows 或是在 Linux 上,也不管你是用 Microsoft .Net Framework 或是 Mono,都可以直接拿他的 Mono.Data.SqliteClient.dll 來使用~
使用方法也很簡單:
- 連接字串:”URI=file:/path/to/file,version=3″。URI指定檔案位置,version則是指定SQLite database版本。
- 從使用範例可以看出,跟 .Net framework 提供的 ADO.Net driver 用法並沒有什麼差別(範例摘錄自SQLite at Mono):
using System; using System.Data; using Mono.Data.SqliteClient; public class Test { public static void Main(string[] args) { string connectionString = "URI=file:SqliteTest.db"; IDbConnection dbcon; dbcon = (IDbConnection) new SqliteConnection(connectionString); dbcon.Open(); IDbCommand dbcmd = dbcon.CreateCommand(); // requires a table to be created named employee // with columns firstname and lastname // such as, // CREATE TABLE employee ( // firstname varchar(32), // lastname varchar(32)); string sql = "SELECT firstname, lastname " + "FROM employee"; dbcmd.CommandText = sql; IDataReader reader = dbcmd.ExecuteReader(); while(reader.Read()) { string FirstName = reader.GetString (0); string LastName = reader.GetString (1); Console.WriteLine("Name: " + FirstName + " " + LastName); } // clean up reader.Close(); reader = null; dbcmd.Dispose(); dbcmd = null; dbcon.Close(); dbcon = null; } }
讀取網頁(4)
更快的方法,就是直接利用 .Net 2.0 提供的 WebBrowser 控制項。
不過,如果用這方法,有兩個缺點:
- .Net 1.1 不適用,因為 class library 沒提供。
- 當直接使用 DocumentText 屬性的時候,WebBrowser 沒有轉換編碼,而是直接以 ascii 傳回。
- 必須是 Windows form 應用程式
那麼,我們要怎麼自行轉換編碼呢?
首先利用 Reflector 來反組譯一下 DocumentText 屬性,這下就可以很清楚看到他是以 StreamReader 去讀取 DocumentStream。
所以當我們確信網頁的編碼是 UTF-8 時,就可以這麼寫了:
Stream documentStream = webBrowser1.DocumentStream; if (documentStream == null) return ""; StreamReader reader = new StreamReader(documentStream, Encoding.UTF8); documentStream.Position = 0; string documentText = reader.ReadToEnd();