Category Archives: IT:.NET Programming

System.Data.SQLite DLL 版本切換 32/64 Bit

專案是在 .NET 底下執行,當然最好還是編譯成 Any CPU,這時指定編譯為 32 Bit 的解法選項就不夠完美。在找解決方案的時候看了 Stackoverflow 的這一篇:

http://stackoverflow.com/questions/7264383/options-for-using-system-data-sqlite-in-a-32bit-and-64bit-c-sharp-world

參考了眾多解決方案都不太符合,後來想到的解法是使用 NSIS 做安裝檔案,預設複製 32 Bit 版本,安裝時當判斷作業系統是 64 Bit 時將 64 Bit 版本複製到應用程式執行路徑,反之則不複製,保持使用 32 Bit 版本。

 

Section "Main Program" MAINSEC

SetOutPath "$INSTDIR"
SetOverwrite ifnewer

; Those files are included with the installer
File /nonfatal /a /r ..\bin\Debug\en\
File /nonfatal /a /r ..\bin\Debug\zh-Hans\
File /nonfatal /a /r ..\bin\Debug\zh-Hant\
File ..\bin\Debug\App.exe
File ..\bin\Debug\App.exe.config
File ..\bin\Debug\System.Data.SQLite.dll
File ..\bin\Debug\System.Data.SQLite.xml
File /nonfatal /a /r ..\bin\Debug\Tools\

;Store installation folder
WriteRegStr HKCU "Software\FETAG\MyApp" "" $INSTDIR

;Create shortcuts
CreateDirectory "$SMPROGRAMS\MyApp"
CreateShortCut "$SMPROGRAMS\MyApp\App.lnk" "$INSTDIR\App.exe"
CreateShortCut "$SMPROGRAMS\MyApp\UnInstall.lnk" "$INSTDIR\Uninstall.exe"

CreateShortCut "$DESKTOP\MyApp.lnk" "$INSTDIR\App.exe"

;Create uninstaller
WriteUninstaller "$INSTDIR\Uninstall.exe"

; x32 or x64 DLL
!include "x64.nsh"
${If} ${RunningX64}
; MessageBox MB_OK|MB_ICONSTOP '64 Bit'
${Else}
; MessageBox MB_OK|MB_ICONSTOP '32 Bit'
CopyFiles "$INSTDIR\Tools\System.Data.SQLite.dll" "$INSTDIR\System.Data.SQLite.dll"
${EndIf}
SectionEnd

另外一個 AssemblyResolver 的方法看起來還是太麻煩了。

 

ICSharpCode.SharpZipLib – Sample Code for zip extract

沒有想到商業版的 ZIP Component 問題那麼多,先前公司的政策就是要使用商業版本的元件,因為在碰到問題的時候可以得到較多的支援,當時為了壓縮解壓縮,有同仁就測試並且推薦了 IPWorksZipNETV7, 接下來的程式當然是使用它來進行開發了。後來發行的程式有 User 出現這個元件的 License 過期的問題,問題是程式已經跑了一段時間了,所以問題不是在發行的程式,而是在這個元件的版權處理,於是換成 ICSharpCode.SharpZipLib 這個免費且開源的元件,後面就沒有再出問題了。

接下來又有另外的程式也發生相同的情況,解決方法依舊,看來用商業版也是存在一些問題,開源的元件,如果自己可以掌控,就用開源的會比較省心吧。

下面留一段 Sample Code 方便日後參考。

public static string ExtractFile(string DownloadFileName)
{
    string destFile = "";
    try
    {
        ZipInputStream zipIn = new ZipInputStream(File.OpenRead(DownloadFileName));
        string ExtractToPath = ConfigurationSettings.AppSettings["BackupPath"].ToString() + "\";
        ExtractToPath = ExtractToPath.Replace("{APPPATH}", AppDomain.CurrentDomain.BaseDirectory);
        ZipEntry entry;
        if ((entry = zipIn.GetNextEntry()) != null) //ONLY ONE FILE
        {
            FileStream streamWriter = File.Create(ExtractToPath + entry.Name);
            long size = entry.Size;
            byte[] data = new byte[size];
            while (true)
            {
                size = zipIn.Read(data, 0, data.Length);
                if (size > 0) streamWriter.Write(data, 0, (int)size);
                else break;
            }
            streamWriter.Close();
            FileInfo fi = new FileInfo(ExtractToPath + entry.Name);
            destFile = ExtractToPath + DateTime.Now.ToString("yyyyMMddHHmmss") + fi.Extension;
            // RENAME FILE
            if (File.Exists(destFile)) File.Delete(destFile);
            File.Move(ExtractToPath + entry.Name, destFile);
        }
    }
    catch
    {
        Console.WriteLine("ERROR: Error while extract zip file.");
    }
    return destFile;
}

LumiSoft.Net Sample Code – POP3_Client with attachments

LumiSoft.Net 包含了很多好用的網路相關 Class, 雖然自己已經收集了一些 Ftp Client, Pop3 Client 等的小 Class, 不過對於這種 Open Source 而且程式經過許多人驗證過的 Class Package 應該要多多支持才是,趁著使用的 Pop3 Client 有點 Bug (部份特殊的 Attachment 抓不到, 如 Pure Text format message attachments) 寫了簡單的測試程式碼,準備要來換掉原先使用的 Class,也許以後的專案會盡量用它了吧。

POP3_Client pop3 = new POP3_Client();
pop3.Connect("mail.fetag.net", 110, false);
pop3.Authenticate("username", "password", false);
POP3_ClientMessageCollection cmc = pop3.Messages;
foreach (POP3_ClientMessage cm in cmc)
{
    byte[] bytes = cm.MessageToByte();
 
    Mail_Message m = Mail_Message.ParseFromByte(bytes);
    string Subject = m.Subject;
    foreach (MIME_Entity entry in m.Attachments)
    {
        string FileName = entry.ContentDisposition.Param_FileName;
        byte[] data = ((MIME_b_SinglepartBase)entry.Body).Data; 
        FileStream fs = null;
        fs = new FileStream(@"d:" + FileName, FileMode.Create);
        fs.Write(data, 0, data.Length);
        fs.Close();
    }
}

Lightweight Rich Text Editor 的 Postback 問題

在上一篇 Lightweight Rich Text Editor (RTE / WYSIWYG) plugin for jQuery 中曾經提到:如果曾在此 Editor 上切換 html/css 時, 其接收方式就必須改為 Request.Form 的方式接收, 原因為何呢?? 我們必須先去瞭解此 Editor 切換 html/css 的方式以及 Post 時的狀況…

該 Editor 使用方式非常簡單, 只需使用下列源碼即可(假設已經有個 class 為 rte 的 textarea )

=====[ Code Start / JavaScript (MSIE 5.5 DOM), with (Jscript) Windows Script Host ]=====
$(‘.rte’).rte({
    css: ‘default.css’,
    controls_rte: rte_toolbar,
    ontrols_html: html_toolbar
});

請自行下載該源碼, 以下將節錄部分源碼加以說明…

=====[ Code Start / JavaScript (MSIE 5.5 DOM), with (Jscript) Windows Script Host ]=====
lwRTE.prototype.enable_design_mode = function() {
    // …. 省略    
    if($(self.textarea).attr(‘name’))
        self.iframe.title = $(self.textarea).attr(‘name’);
    var content    = $(self.textarea).val();
    $(self.textarea).hide().after(self.iframe).remove();
    self.textarea    = null;
    // …. 省略    
}

self.textarea 為一 Element, 就是第一段以 $(‘.rte’) 方式傳入的 textarea; 而 self.iframe 也是一個 Element, 將是 HTML 編輯器的編輯區塊…

lwRTE.enable_design_mode 的作用是將 Editor 變更為 HTML 編輯模式…
請注意上段源碼的 $(self.textarea).hide().after(self.iframe).remove();,
源碼會先將 self.textarea 的 name attribute 存放於 self.iframe 的 title attribute 中…
然後把 self.textarea 隱藏後, 在該 Element 後面插入 self.iframe, 再將 self.textarea 移除… 請注意是移除不是隱藏喔…

我們再看另一段源碼…

=====[ Code Start / JavaScript (MSIE 5.5 DOM), with (Jscript) Windows Script Host ]=====
lwRTE.prototype.disable_design_mode = function(submit) {
    var self = this;
    self.textarea = (submit) ? $(‘<input type=”hidden” />’).get(0) : $(‘<textarea></textarea>’).width(‘100%’).height(self.height).get(0);
    // …. 省略
    if(self.iframe.title)
        self.textarea.name = self.iframe.title;
    // …. 省略
    if(submit != true) {
        $(self.iframe).remove();
        self.iframe = null;
        self.activate_toolbar(self.textarea, self.toolbars.html);
    }
}

在lwRTE.disable_design_mode的作用是將 Editor 變更為純文字的編輯模式…
此函示中, 會依 submit 來決定是新增 HiddenField 還是 TextArea, 並將新增 Element 中的 name attribute 設定為 self.iframe 的 title attribute, 當 Postback 時, 才能將其 html 內容回傳…
在重複切換 html/css 多次後, 將會造成 self.textarea 多次 create & remove, 所以當 Postback 後, Server Side 會收到多份以原 textarea 為 name 以及同樣 name 的 HiddenField 資料…

不曉得原因為何, 但如果 jQuery 有確實 remove element 的話, 照理來說是不應該會有這種情況發生, 但為解決這個問題, 所以必須使用在上一篇提到的方法 Request.Form, 因為在ASP(ASP.NET)中, POST 收到的資料, 如果 name 相同的話, 將會以 Array String (string1, string2, …) 的方式傳送, 所以必須以Request.Form 的方式加以接收並擷取…

而擷取資料的方式為 :

=====[ Code Start / C Sharp (Include .NET Framework 2.0) ]=====
string[] arr = Request.Form.GetValues(TextBox1.UniqueID);
Label1.Text = arr[arr.Length – 1];

為何擷取最後一個的值, 因為 lwRTE 所插入的 HiddenField 是插入在原有 TextArea 的後面, 所以取最後一個才是正確的 html 內容

以上說明, 希望能幫到需要的人…

[.NET] 修改 Form 驗證的 Session Timeout 值

原因是使用者登入後操作了一陣子,然後去作別的事 (倒水、泡茶、喀瓜子還是聊八卦),過了一段時間後回來再點系統的任何一頁,會再次出現登入視窗,試了在 Global.asax 加上 Session.Timeout 值為 1440 (一天) 沒有用處,Login.aspx 的程式裡也沒有設定其它的 Session Timeout 值,用 Cookie Viewer 查看系統在 Login 後送出來的 Cookie,發現餅干的過期時間還是 30 分鐘 (等於是 Global.asax 中設的無效),最後找到是在 Web.Config 裡的 authentication tag 可以設定 Form 驗證的 Session Timeout 值,範例如下:

<authentication mode="Forms">
    <forms loginUrl="login.aspx" protection="All" timeout="1440" slidingExpiration="true" />
</authentication>

改完再測試餅干的過期時間,變成一天了,收工~

記憶體回收 (EmptyWorkingSet)

LifeHacker 上看到一個叫作 Minimem 的工具,主要是用來清除系統中不用的記憶體,可以設定幾秒執行一次,也可以設定針對哪一些使用記憶體量比較大的程式進行記憶體回收的動作。下載來稍微玩了一下,發現有點用處,類似的程式有 Freemem 之類的,以前一直想瞭解這些程式的運作原理,剛好 Minimem 是 .NET Framework 3.5 的程式,所以就可以拿它來 “解剖” 一下,看看實際的工作原理是甚麼。

用 Reflector 看了一下,主要是呼叫一個叫作 EmptyWorkingSet 的 Method 來進行,而它僅是一個 Interface,調用 psapi.dll 裡的 EmptyWorkingSet 這個 Method。

[DllImport(“psapi.dll”)]
private static extern int EmptyWorkingSet(IntPtr hwProc);

再 Google 一下 “EmptyWorkingSet”,發現它就是利用 Windows 提供的 API 來進行記憶體回收,僅此而已,沒有其他令人驚豔的程式碼與功能,原來這僅僅是一個系統 API 而已呀。先前以為記憶體回收是一個怎麼樣困難的技術,現在發現原來困難的技術已經被包成系統 API (“某些”系統,就是需要這些 API),很多的工具都可以利用呼叫這個 API 來達到回收效果,下回自己寫的程式吃太多記憶體的話,可以試一下寫一個會自我回收記憶體的程式。

[Reference]
http://msdn.microsoft.com/en-us/library/ms682606.aspx
http://www.google.com.hk/codesearch?q=EmptyWorkingSet&ie=UTF-8&oe=utf-8&rls=org.mozilla:zh-TW:official&client=firefox&um=1&sa=X&oi=codesearch_group&resnum=4&ct=title

至於 Minimem 嘛,仍有它的功能在,作為一個設定固定時間、針對 Process 記憶體使用量執行的介面程式,不過我還是覺得它應該要寫成 Windows 的 Service 比較好。

[Update 2008-09-24]

出差在飯店晚上無聊的時候弄了一個 Service 的版本,暫時叫作 More Memory V1.0,可以在下面的連結下載:
http://groups.google.com/group/Autorun-DIY/web/MoreMem100.zip?hl=zh-TW
安裝很簡單,就是建一個目錄,把檔案都放進去,然後跑一下 Install.bat,接著到[控制台][系統管理工具][服務] 裡頭就可以看到 FETAG – More Memory Service 把它設為 “啟動” 就可以了。要移除的話就執行 UnUnstall.bat 即可。

TcpTrace

試著從 .NET 呼叫 WebMethod 所提供出來的 Web Service時,發現了一個 Fatal Error,導致程式開發的工作無法進行下去,.NET 的 Exception 所給的錯誤訊息並不是很完全,就算看到 Inner Exception 也不一定有效判斷,有可能讓人誤判錯誤的真正發生點。安裝了 TcpTrace 這個工具程式,在本機實作了一個 Proxy 機制來補捉 Client 與 Server 之間的溝通訊息,果然很快的就發現錯誤。原來是 WebMethod 那邊有一個 Adapter 沒有初始,導致嚴重的錯誤,跟自己寫的程式一點關係都沒有。

TcpTrace
http://www.pocketsoap.com/tcpTrace/

Microsoft ACT 的 Stand Alone Installation

ACT (Application Center Test) 是一個 Windows 平台上很好用的壓力測試工具,我經常會使用它來對伺服器進行上線前測試,在 VS.NET 2003 的環境安裝之後就有這個好用的程式可以使用了。最近的一次測試中,我並不想在執行測試的機器上裝 VS.NET 2003,所以在網路上找了一些方法,發現有人用 Register Monitor 花了一整天的時間來找出 Workaround,以下就是方法:
Continue Reading

ASP.NET 相關的參考網站

www.ASPAlliance.com
www.ASP.net
www.CodeProject.com
www.c-sharpcorner.com
www.DevX.com
www.DotNetJunkies.com
www.SearchVB.com
www.TheServerSide.net

快速建置支援 log4net 的 ASP.NET WepApplication

log4net 的 Example 並沒有寫得很清楚,在網路上的一些 Sample Code 也沒有把版本交待清楚,甚至一些程式碼跑不動,繞了很多冤枉路之後弄了一個簡單的步驟,以下只留下 FileAppender 跟 MS-SQL 兩個 Appender,需要其它 Appender 的再手動去加。
Continue Reading

Copyright © 2017. Powered by WordPress & Romangie Theme.