2009年12月19日 星期六

Html.Encode 的簡寫

在防範 XSS 攻擊時,常常教導同事,要將輸出的字串 Encode, 例如

  • 在CodeBehind 時要 HttpUtility.HtmlEncode(myString)
  • 在Web Form 的 aspx中,要 <%= HttpUtility.HtmlEncode(myString) %>
  • 在MVC 的 View中,要<%= HtmlEncode(myString) %>

在Web Form的寫法實在太長了,而MVC 的寫法稍為短了一些,但也好不到哪裡去。

因此,在 ASP.NET 4 中介紹了新的語法 <%:  … %>

上述的後兩個範例就可以簡寫成

<%: myString %>

大幅地縮短了 coding 時間。真是好設計。

2009年12月18日 星期五

在 master page 中引用 image

在 master page 中使用資源,如 image, js 等,需要更多的技巧。

舉例來說,在 aspx 中引用 image 是相當簡單的事
<td background=”./imgs/a.jpg”>
只要該頁面與 a.jpg 的相對位置是固定的即可。

而 master page 是要給每個頁面 (aspx) 來套用版型的,在 master page 中引用 image 會面臨相對位置不固定的問題。

解決方法是:
<td background='<%=ResolveUrl("~/imgs/a.jpg") %>' >

如果要使用在 css block 時,可使用如下的寫法
<style>
.def02 {
background-image: url(<%= Page.ResolveUrl("~/imgs/a.jpg") %>);
}
</style>

2009年12月15日 星期二

CAT.NET 容易 OutOfMemory

繼上一次 CAT.NET 初用後,又使用不少次。原因當然還是要幫同事找出 Sql Injection 的問題。

找出 Sql Injection 漏洞根本不是人做的,因為我們無法像父母親照顧小孩一樣,隨著專案不同階段來檢查專案的程式碼是否有 Sql Injection 問題。

而 CAT.NET 除了可以幫我們找出該類的問題外,更可以與開發工具結合,直接與顯示出問題發生的路由。

可惜的是,CAT.NET 工具非常秏記憶體,而一個 32 位元的程式,預設只能吃到 2GB。又與 Visual Studio 結合後,最多只能吃到 1.2 GB 左右而已。

為了解決這個問題, CAT.NET 出了 64 位元版,該版本就是要解決記憶體不足的issue。但,Visual Studio 並沒有 64位元版。換句話說,CAT.NET 64 bit version 無法與Visual Studio 結合,這是該版本的一大不方便的地方。

使用 64 位元版,只能使用 command line 的方式來執行。說明文件,則可以解壓縮後找到 CAT.NET.chm。該說明相當詳細了,不必在這裡重複。

我最常用的指令,如下。意思是找到 c:\dll 下所有的 dll ,分析後將報告輸出成 c:\dll\report.xml。

CATNETCmd64 /file:C:\dll\*.dll /report:c:\dll\report.xml

最後,將該 xml 改套用 \CATNETx64CTP\CAT.NET\Config\report.xsl ,即可看到輸出的報表。也就是加入 xml-stylesheet 這一行於 xml 檔。

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="report.xsl" ?>
<Report xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Analysis>

後記:
    讀者問到:「如果專案是以網站(WebSite)的型式建置開發,因此建置時不會產生dll」時該怎麼辦?

    由於CAT.NET的運作原理, 是「看」assembly 的運作方式是否有問題,然後再將問題對後到原始程式碼,顯示出問題的path。因此必須有 assembly 才能運作。

    解決方法,是先使用ASP.NET 編譯工具 (Aspnet_compiler.exe)將WebSite compile 成 dll後,再執行 CAT.NET 進行分析。

2009年11月30日 星期一

VS2010 的 Coded UI Test 在 WPF 應用程式上無效?

試著使用 VS2010 的新測試功具 Coded UI Test 時,發現在WPF應用程式上無法建立 Assertion。

為何呢?如下圖,原因出在 「An update for windows Automatin API 3.0 must installed to enable…」

image

原來,WPF 的Coded UI 測試,要使用 Assertion 功能時,需要安裝一個 Update,見 Description of the Windows Automation API 及安裝對應的版本即可

2009年11月27日 星期五

減重的十件必須知道的事

減重的十件必須知道的事

  1. Don't skip meal : 每一餐都不能省略
  2. Use smaller plates : 用小盤子
  3. Count your calories : 計算吃的卡路里
  4. Don't blame your metabolism : 不要怪自己的新陳代謝不好
  5. Protein staves off hunger pangs : 蛋白質比較不會餓
  6. Soup keeps you feeling fuller for longer : 湯類較有飽足感
  7. The wider the choice, the more you eat : 愈多選擇,吃的愈多
  8. Low fat dairy helps you excrete more fat : 低卡的奶製品幫助排出脂肪
  9. Exercise goes on burning fat, eve while you sleep: 運動後將持續減重,即使隔天你只是在睡覺
  10. Keep moving and lose weight : 讓自己不停地動,就能減重。例如不搭電梯,改走樓梯。

2009年11月20日 星期五

Office 2010 Beta 已經出來了

已經於 11/16 日出來了公開測試版。

可到此處  公開下載  下載程式。安裝時需要key,需要到處理 註冊

image

已從CTP 版試用了好一陣子,沒有什麼問題。
目前只有英文版、簡體中文版、日文版等可用,還沒有繁體中文版。

2009年11月18日 星期三

Asp.Net: File does not exist

在幫別人除錯 asp.net 時,發生了如下的錯誤。

Type : System.Web.HttpException, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Message : File does not exist.
Source : System.Web
Help link :
ErrorCode : -2147467259
Data : System.Collections.ListDictionaryInternal
TargetSite : System.IO.FileInfo GetFileInfo(System.String, System.String, System.Web.HttpResponse)
Stack Trace :    at System.Web.StaticFileHandler.GetFileInfo(String virtualPathWithPathInfo, String physicalPath, HttpResponse response)
   at System.Web.StaticFileHandler.ProcessRequestInternal(HttpContext context)
   at System.Web.DefaultHttpHandler.BeginProcessRequest(HttpContext context, AsyncCallback callback, Object state)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

但,這是如何發生的呢?並沒有指明是哪一個 page 發生錯誤。

首先,這是有故事的。
我幫同事做了 exception 的 log,也就是發生錯誤時會例外資訊記錄到檔案上。後來發現只要登入後,一到網站首頁,記錄檔就會看到這樣的錯誤資訊。

再來,我發現該專案是使用 Web Development Server 開發的,而不是使用 IIS。這一點我一直不信任 Web Development Server,因為該模式是使用開發人員的權限,而不是真正的 IIS 的權限。未來在正式機器上部署後,還會有權限不正確的變數。

更奇妙的是,我發現只有使用 Web Development Server 才會發生這種現象,而host 在IIS 時是不會發生的。

最後,我在記錄的 handler 上,再寫出HttpContext.Current.Request.FilePath 。令人不解的是,FilePath 竟然是 “/images/default_12.jpg”!!

我的解讀如下:

當使用 IIS 6.0 時,IIS 一遇到 jpg 檔時,就直接找 jpg 檔案後輸出。所有過程與 asp.net 無關。

而使用 Web Development Server , 則所有的檔案皆使用 asp.net 來處理。當遇到 jpg 檔時,會使用 StaticFileHandler 來處理。

因此,不要使用 Web Development Server 來開發。因為畢竟與 IIS 的運作不一樣。

2009年11月16日 星期一

無法載入 DLL 'VSCover90': The specified module could not be found. (發生例外狀況於 HRESULT: 0x8007007E)

開發程式後,執行測試。由於沒有耐心等測試跑完,就急著放 assembly 到正式機上了。哪知一執行,網頁竟跑出

無法載入 DLL 'VSCover90': The specified module could not be found. (發生例外狀況於 HRESULT: 0x8007007E)

 

原來,我在執行測試時,也同時收集 code coverage (程式覆蓋率)。為了能收集該資料,Visual Studio 看來有放一些 sampling 的程式到 assembly上。
而 Visual Studio 正執行測試時,我就急著放 assembly到正式機了。因此會出現這樣的怪事。

解決方法呢?等測試執行完後,再部署 dll 即可。

2009年11月2日 星期一

取得文件庫中所有簽出文件的所有權

有同事一次將4000 多個檔案放到MOSS 的文件庫後,卻沒有簽入。此時,再請他簽入時,卻只能一個一個檔案簽入了。

救命啊!果然不是人做的。此時只有使用系統帳號,取得所的已取出文件的所有權,然後再以系統帳號再簽入。

可是,還是不行。因為一次要處理的文件太多了,全選並取得所有權時,伺服器會出現 Sql Server Parameters 最多只能有 2100 個的限制。

只好寫程式了。以下就是我寫的程式。

private static void TakeOwnershipOverAllCheckoutFiles(string sitePath, string refWeb, string listName)
    {
      using (SPSite site = new SPSite(sitePath))
      {
        SPWeb web = site.OpenWeb(refWeb);
        SPList list = web.Lists[listName];

        SPDocumentLibrary library = (SPDocumentLibrary)list;

        IList<SPCheckedOutFile> files = library.CheckedOutFiles;

        foreach (SPCheckedOutFile file in files)
          file.TakeOverCheckOut();
      }
    }

這樣一來,就避免了Web UI 的限制。

2009年10月27日 星期二

Visual Studio 2005 sp1 在 Windows 2003 Server 安裝失敗

最近為了看別人的 code,需要在 Virtual PC 上安裝 Windows 2003 + Visual Studio 2005 + SP1。無奈,一直安裝失敗。

看了一下 event log,我有多種錯誤發生過。

  1. 不允許安裝 C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\ZNW1C\VS80sp1-KB926601-X86-ENU.msp,因為軟體限制原則處理中發生一個錯誤。物件無法被信任。
  2. Product: Microsoft Visual Studio 2005 Team Suite - ENU -- The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is 2755. The arguments are: 1612, C:\WINDOWS\Installer\3617f.msi,
  3. 產品: Microsoft Visual Studio 2005 Team Suite - ENU - 無法安裝更新 'Microsoft Visual Studio 2005 Team Explorer - ENU Service Pack 1 (KB926601)'。錯誤碼是 1603。其他可用資訊在記錄檔案 C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\VS80sp1-KB926601-X86-ENU\VS80sp1-KB926601-X86-ENU-msi.0.log。
  4. Product: Microsoft SQL Server Native Client -- Error 1706. An installation package for the product Microsoft SQL Server Native Client cannot be found. Try the installation again using a valid copy of the installation package 'sqlncli.msi'.
  5.  

在安裝的過程中,各式各樣的錯誤都可能發生,而且也會發生在不同的安裝階段,有時發生在解壓縮時(如2),有時發生在安裝(如4)。

我記得以前不會啊?看來是新的 windows hot fixes 所造成的。

解法呢?安裝 WindowsServer2003-KB925336-x86-CHT.exe 這個 hot fix 之後重開機,再安裝 Visual Studio 2005 sp1 即可

2009年10月25日 星期日

2009年10月21日 星期三

爆笑經典名句

Direct link: paste.plurk.com/show/25556

爆笑經典名句 

1. 樹多必有枯枝,人多必有白癡

2. 樹不要皮,必死無疑;人不要臉,天下無敵

3. 醫生叫我行光合作用別熬夜

4. 帥有個屁用!到頭來還不是被卒吃掉

5. 騎白馬的不一定是王子,可能是唐僧;帶翅膀的不一定是天使,也可能是「鳥人」

6. 就算是 Believe 中間還是有個 lie

7. 就算是 Friend 最後還是會有個 end

8. 就算是 Lover 最後還是會 over

9. 就算是 Forget 也要先 get 才行

10. 就算有個 Wife 心裡也要假設 if

11. 壓力始終來自於新台幣

12. 不是隨便一個地球人就可以學會火星話的

13. 君子報仇,三年不晚;小人報仇,一天到晚

14. 『在塞納河畔哭泣』和『在濁水溪旁哭泣』這兩者究竟有什麼不同呢?

15. 人生,不過比當歸長一點

16. 懷才就像懷孕,時間久了才能讓人看出來

17. 客戶是神,因為客戶不是人

18. 前程四緊就是:手頭緊、眉頭緊、衣服緊、時間緊

19. 青春就像衛生紙;看著挺多的,用著用著就不夠了

20. 幸福離我們很近,但是我們都忘了靠近

21. 能者多勞,疲勞的勞!

22. 問君能有幾副肝,恰似一串鞭炮爆不完

23. 男人過了五十歲只剩下一張嘴,過了六十歲就只有兩個地方會變硬:肩膀硬跟肝硬

24. 福利不是問題,問題是沒福利;錢不是問題,問題是沒錢

25. 今日事今日畢,過了今日就不必

26. 皮夾裡的發票永遠比鈔票多

27. 既然上了賊船,就要做個成功的海盜

28. 我不是隨便的人,但我隨便起來不是人

2009年10月20日 星期二

在 Windows 7 下刪除 Windows Vista 的 Windows 目錄

標題看起來有點怪。但這是常見的。

我在2006 年底安裝了 Windows Vista。
到了今年,為了不讓舊的Vista 不能運作,故安裝 Windows 7 在另一個 partition。

過了三個月,原有的 Vista 已不再需要了,故希望在 Windows 7 下將 Vista 的 d:\windows 刪除。

問題是,怎麼刪都權限不足。

原來,Vista 的權限設計又更完整了,故要刪除,必須先取得 Owner 的權限,再讓自己獲得 Full Control。

要取得Owner 的權限,要以administrator執行 cmd , 下如下的指令

takeown /f D:\Windows /R

之後就可以一般設定權限的方式取得 Full Control 了

VS2010 Beta2 可以在 MSDN Subscriptions 下載了

真是好樣的。等了好久。

image

未來也會公開發佈給一般大眾測試哦!

2009年10月15日 星期四

如何將 Hyper-V 的 vhd 移到 Virtual PC 中使用

因客戶需要,只好將 Hyper-V 中的 vhd 複製一份到 Windows 7 中Windows Virtual PC 使用。

一使用,就只看到游標動了一動,就什麼動靜也沒有。這怎麼回事?

原來,Windows Server 2008 中的 Hyper-V為了效能,更改了HAL 的設計。每更新一個版本,就會更新一次 HAL。HAL 是一個 dll,位於 c:\windows\system32\hal.dll。

要解決這個問題,簡單來說,就是要想辦法手動更換這個hal.dll 到適當的版本。

我所使用的步驟如下

  1. 在原 Windows Server 2008 Hyper-V 中,將 guest OS 的 Intergration Service 移除。以下稱該 VM 為「目標VM」。
  2. 複製 VHD 到 Windows 7。
  3. 找一個已經存在 VM(以下簡稱「已存在VM」),且已存在 VM 的平台與目標VM相同。例如目標VM是 Windows Server 2003,則我們必須找一個也是 Windows Server 2003 的VM。
  4. 設定已存在VM,將目標VM的VHD 設為第二顆硬碟。
  5. 啟動已存在VM後,將 c:\windows\system32\hal.dll 複製到第二顆硬碟相對應的位置,如E:\windows\system32\ 下。
  6. 關閉已存在VM。
  7. 啟動目標VM。完成

2009年10月6日 星期二

微軟的免費防毒軟體:Microsoft Security Essentials

微軟前一陣子推出了免費的防毒軟體 Security Essentials

如果您的電腦沒有安裝防毒軟體,您也不想花錢買,那就下載一吧!

目前 (2009/10/05)尚未出繁體中文版,而且也不讓台灣區來下載。

怎麼辦呢,就偷改一下設定吧。只需要在 IE 上,修改網際網路選項。將「一般」頁下的「語言」,新增一個英文(en-US)即可。

過程見下圖(以英文的 IE 為範例)

執行「網際網路選項」

image

點擊「一般」頁下的「語言」鍵

image

新增一個英文(en-US),並調整到最上方

image

再到 Security Essentials ,就可以進行下載了。

2009年10月1日 星期四

如何將 Visual Studio Load Test 的結果匯出成報表

Visual Studio 2005 Team System Tester Edition 上,可以執行 LoadTest,但如何將其結果匯出成 Excel,給客戶作為壓力測試報告呢?

這就必須使用 CodePlex 上的開源碼程式 Microsoft Visual Studio Team System Load Test Reporting Sample 了。

解開壓縮檔後, 在 doc 目錄下有 InstallationGuide.doc 說將如何安裝。安裝的過程簡單,只是需要有 Report Service 的概念。

進行壓力測試時,需指定 Load Test Result Store 設定到 Database Server, database 設為 LoadTest.

image

而 LoadTest 的 Run Settings, 也需將 Storage Type 設為 Database,才能將結果寫到資料庫中。

image

執行完壓力測試後,可使用 結果匯出到http://server/VSTSCustomReports/Default.aspx 檢視結果。如下圖。

 

clip_image002

clip_image004

2009年9月30日 星期三

單元測試(5): 可測試性

這個系列,請見
單元測試(1): 什麼是單元測試
單元測試(2): 單元測試的好與壞
單元測試(3): 單元測試的好與壞2
單元測試(4): 單元測試的好與壞3

由前面的文章可知,單元測試的好壞,相當依賴於原程式的可測試性。為了增加可測試性,我們可以增加/修改原程式的架構,以便進行測試。

舉例來說:
1  原為 private 的方法,為了可測試性,改成 internal
2  方法設成 virtual,以利 mock
3  原為 static 的方法,改成 instance 的方法,以利 mock

有人會質疑,這些步驟,是真的需要嗎?
最有名的例子,就是 asp.net 了。原來有個 System.Web 的 namespace,其下的類別雖然相當好用,但卻難以進行單元測試。到了asp.net MVC後,增加了 System.Web.Abstractions.dll 的類別庫,其下的類別都與 System.Web 的類別相似,甚至可以找到對應的類別。但 System.Web.Abstractions.dll 下的類別都進行了抽象,以利進行單元測試。

System.Web,可看到其下有相當多的類別是以 Base結尾,這些就是為了可測試性所增加的類別。例如HttpApplicationState不容易進行單元測試,就增加了 HttpApplicationStateBase 這個類別,利於進行單元測試。所以我們可以觀察到,兩者的成員(見 HttpApplicationState MembersHttpApplicationStateBase Members)幾乎是一樣的,只是 Base 的成員幾乎都是可被 override 。

2009年9月16日 星期三

單元測試(4): 單元測試的好與壞3

這個系列,請見
單元測試(1): 什麼是單元測試
單元測試(2): 單元測試的好與壞
單元測試(3): 單元測試的好與壞2

上次首次提到了「可測試性」的重要,這一次舉另外一個例子。
這段程式,是一個將一段xml寫到一個特定目錄的檔案。

 
using System;
using System.IO;
using System.Xml.Linq;

namespace ClassLibrary2
{
  public class Class1
  {
    public void WriteXmlToFile(DateTime date)
    {
      XElement el = new XElement("Order", new XElement("OrderDate", date));
      File.WriteAllText(@"c:\temp\result.xml", el.ToString());
    }
  }
}

相同的,如下的測試程式,要如何聲明(Assert)是否正確呢?

using System;
using ClassLibrary2;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace TestProject1
{
  [TestClass()]
  public class Class1Test
  {
    [TestMethod()]
    public void WriteXmlToFileTest()
    {
      var target = new Class1();
      target.WriteXmlToFile(new DateTime(2009, 1, 1));
    }
  }
} 

真的沒辦法嗎?我們也可以將輸出的結果檔案讀出來。並與預期的結果比對。當然,這樣是不好的。

BAD

using System;
using ClassLibrary2;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;

namespace TestProject1
{
  [TestClass()]
  public class Class1Test
  {
    [TestMethod()]
    public void WriteXmlToFileTest()
    {
      var target = new Class1();
      target.WriteXmlToFile(new DateTime(2009, 1, 1));
      string result = File.ReadAllText(@"c:\temp\result.xml");
      Assert.AreEqual(@"
  2009-01-01T00:00:00
", result);
    }
  }
}

這樣有什麼不好呢?除了前次提到的與檔案系統相關外,又有什麼不好呢?目錄指定的路徑是客戶指定的,除可以改設定到 config 檔上,其餘沒有什麼好談的。

其實,這一段的確是可以測試的。但需要強調的事情是:可測試性不佳。
如果客戶要求的是將 xml 資料以 email 或 web service 方式傳出去呢?那要如何測試該段 xml 是正確的呢?難道要去讀對方 web service 是否收了了訊息,或 email server 是否收了 email?

我的解答如下:改變 method 的 signature

using System;
using System.IO;
using System.Xml.Linq;

namespace ClassLibrary2
{
  public class Class1
  {
    public string WriteXmlToFile(DateTime date)
    {
      XElement el = new XElement("Order", new XElement("OrderDate", date));
      string result = el.ToString();
      File.WriteAllText(@"c:\temp\result.xml", result);
      return result;
    }
  }
}
測試程式碼如下:
using System;
using ClassLibrary2;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;

namespace TestProject1
{
  [TestClass()]
  public class Class1Test
  {
    [TestMethod()]
    public void WriteXmlToFileTest()
    {
      var target = new Class1();
      string result = target.WriteXmlToFile(new DateTime(2009, 1, 1));
      Assert.AreEqual(@"
  2009-01-01T00:00:00
", result);
    }
  }
}

只有一點小改變:該method 回傳 xml 的結果。
質疑聲:「什麼?為什麼要回傳 xml 呢?又不需要!只會浪費時間,效能變差」

這一點,真的不好回答。回到一個問題,什麼是需求?什麼樣的事情才是需求?
我們常將需求分成「功能需求」與「非功能需求」。功能需求是指客戶真的需要的功能。非功能需求又可再細分安全性、效能、可維護性、…等。

為了安全性,會加上一堆的 System.Security 的類別與物件。
為了效能,會使用多執行緒的方式加快程式執行速度、加上效能物件以量測正式機上的效能。
為了可維護性,更會以物件導向、再搞出Multi-layer, SOA, MVC 等架構。

那「可測試性」不也是一種「非功能需求」嗎?為了「可測試性」,當然也可以將某一 method 由 void 改成回傳 string 啊!

結論

為了可測試性,可以改變程式的 signature。

2009年9月11日 星期五

Run Code Metrics 出現錯誤

在使用 VSTS 的 run code metrics 功能時,發生了無法分析的錯誤。

An error occurred while calculating code metrics for target file ‘xxx.dll’  The following error was encountered while reading module 'Microsoft.SharePoint': Could not resolve type: T ObjectModel

這裡有個特殊符號,可不是我隨便打的。整個錯誤訊息 copy 下來就有的。

這該怎麼解呢?還好之前的 SandCastle 的安裝及使用 的經驗,知道這類的程式,一定程度上需要了解 dll 的關聯。我的例子,是我reference了 Sharpoint 的 元件 Microsoft.SharePoint.dll。在我的 project 中,是可以被 compile 並執行的。但是 Microsoft.SharePoint.dll 在執行時期,需要引用 Microsoft.SharePoint.Security.dll。
Microsoft.SharePoint.Security.dll 並不在我引用的範圍中。因此分析出錯了。

要解決這個 issue,只需要手動地再加入 reference Microsoft.SharePoint.Security.dll 即可。

2009年9月10日 星期四

HttpModule 中使用置換 Response.Filter 為何無效

最近,為了asp.net 的網站安全,被迫加強檢查使用者自行修改 Url 的問題。
例如 http://server/ap/Order/View/1 是目前使用者可以看的訂單1。但若使用者以此類推,修改 Url 為 http://server/ap/Order/View/2 就可以看到訂單2的資料,即使原來該使用者是不能看到的。

為了檢查這方面的問題,特別寫了 httpModule來防止自行修改。原理是加上 hash value. 也就是將 http://server/ap/Order/View/1 的值作 hash,然後加到 Url 上。如 http://server/ap/Order/View/1?h=887766AABB2

這樣應該很完美了。但是,有些網頁就是不能動。原來,我的方法是使用 httpModule 中,將 Respose.Filter 置換成自訂的 Filter。但這個方法在 Server.Tranfer(), Response.End(), Response.Redirect() 時是無效的。

參考文件,見 http://aspnetresources.com/articles/HttpFilters.aspx 

這是相當特殊的狀況,必須記錄下來,以免忘記了

2009年9月9日 星期三

單元測試(3): 單元測試的好與壞2

這個系列,請見
單元測試(1): 什麼是單元測試
單元測試(2): 單元測試的好與壞

另一種常見不好的單元測試,是測試與時間相關的程式。

舉例來說,有個 IsTimeMath() 的 method,要傳回當天的時間是否已過了當年的四分之三。程式大概如下:

 
  public class Class1
  {
    public bool IsMatch()
    {
      DateTime today = DateTime.Today;
      DateTime lastDayInYear = new DateTime(today.Year, 12, 31);
      return ((float)today.DayOfYear) / lastDayInYear.DayOfYear > 0.75f;
    }
  }
不好的測試程式如下
    /// 
    ///A test for IsMatch
    ///
    [TestMethod()]
    public void IsMatchTest()
    {
      Class1 target = new Class1();
      bool expected = false;
      bool actual = target.IsMatch();
      Assert.AreEqual(expected, actual);
    }

當在寫測試程式時,您會發現測試邏輯是想不出來的。原因呢?沒有任何參數需要輸入,卻需要聲明測試是否正確?很怪吧!
既然測試邏輯想不出來,代表原來的需求是錯的嗎?也不是,因為需求的確是「回傳當天的時間是否已過了當年的四分之三」。

那到底是怎麼樣?不是需求的問題,測試也寫不出來,到底該怎麼辦?
原來,追究原因,是 IsMatch 這個方法是難以測試的 (not testable),原因是與時間相關,而時間一直變動。
解決的方法,是讓 method 改成與時間無關,才是可測試的 method。改 IsMatch() 如下

public class Class1
  {
    public bool IsMatch()
    {
      return IsMatch(DateTime.Today);
    }

    public virtual bool IsMatch(DateTime today)
    {
      DateTime lastDayInYear = new DateTime(today.Year, 12, 31);
      return ((float)today.DayOfYear) / lastDayInYear.DayOfYear > 0.75f;
    }
  }

我做了什麼改變呢?我將程式改寫為兩個。第一個 IsMatch() 呼叫 第二個 IsMatch(DateTime today)。主要的邏輯放在第二個 IsMatch(DateTime today)
改變的動機,是
1. 第二個 IsMatch(DateTime today) 才具可測試性,才寫得出測試邏輯來
2. 第一個 IsMatch() 符合原需求。

這樣一來,IsMatch(DateTime currentDate) 才是可測試的,Unit test 才寫的出,而且也符合需求。

結論

我們所撰寫的程式,必須是符合「可測試性」,才有辦法寫出好的單元測試。

2009年9月7日 星期一

OpenXml Sdk 2.0

之前提到過 不建議在 asp.net 上使用 office Interop 的原因,那在伺服器端需要生成 Office 文件時,究竟用什麼方法較適當呢?我建議使用 xml 的方法。

Office 2003 有自己的 xml格式。到了 Office 2007 時代, Microsoft 提交了 Open Xml Format 。建立 xml 的資料是純文字的,任何平台都能建立文件。

但是,了解 xml 的格式是需要相當的時間,尤其這些 Word, Excel 等格式,充滿著許許多多的物件及相對應的 xml element。為了讓開發 Open Xml 更為方式,微軟推出了 OpenXml Sdk,目前推到了 2.0 , (仍為 CTP 版)。

我初步使用的心得:

  1. 還是在操作 xml:當初以為是像 Office automation 的物件方式在生成文件,其實這個想法是錯的。
  2. 已經相當成熟了:雖然是操作 xml,但配合多個 Tool,反而更能深入了解該 xml format 的用意。
  3. 是格式,而非應用程式:例如製作 doc的目錄 (Table of Content),這是一個 Word 的功能,因此只能由 Word 應用程式來生成。在 xml 中是沒有這個功能的。當然,我們可以寫一個類似的功能,直接生成文件目錄的 xml。但,蠻花時間的哦!

2009年9月5日 星期六

MVC (3): Controller

接收使用者的 Request ,經由 Url routing 後,第一關來到的是 Controller。
Controller 的責任可參考 MVC (1): Asp.NET MVC 概念說明

Controller 的責任是:處理資料 (Model) 並挑選一個 View 回應給 Client。由 Routing ,到 Controller 處理Model,最後到 View,一氣喝成。一個關節沒弄好,就會出錯。

舉例來說,預設的 routing table 如下:

routes.MapRoute( 
"Default",                                              // Route name 
"{controller}/{action}/{id}",                           // URL with parameters 
new { controller = "Home", action = "Index", id = "" }  // Parameter defaults 
); 
http://localhost/Home 則會找到 HomeController 的 Index Action。請參考下例
[HandleError]
    public class HomeController : Controller
    {
        //http://localhost:4041/Home/
        public ActionResult Index()
        {
            return View();
        }

        //http://localhost:4041/About/
        public ActionResult About()
        {
            return View();
        }

        //http://localhost:4041/About/3
        public ActionResult About(int id)
        {
            ViewData["id"] = id;
            return View();
        }
    }
如果執行 http://localhost:4041/Home的要求,但 HomeController 沒有 Index() 這個 Action的話,會出現什麼狀況呢?答案是 The resource cannot be found.

controller要如何「挑選」View 呢?答案是 View() 這個 Method
當我們使用 return View() 時,會使用同 Action 的 View。

舉例來說,
[HandleError]
    public class HomeController : Controller
    {
        //http://localhost:4041/Home/
        public ActionResult Index()
        {
            return View();
		//與 return View("Index") 相同
        }
    }
如果,硬要挑選其他名稱的 View,就要指定 View 的名稱。如下例

[HandleError]
    public class HomeController : Controller
    {
        //http://localhost:4041/Home/
        public ActionResult Index()
        {
            return View("List"); //雖然是 HomeController下的 Index Action,但指名挑選名為 List 的 View
        }
    }

2009年9月3日 星期四

The SessionStateTempDataProvider requires SessionState to be enabled

'/EPWeb' 應用程式中發生伺服器錯誤。
--------------------------------------------------------------------------------

The SessionStateTempDataProvider requires SessionState to be enabled.

面對這樣的錯誤時,實在不知如何下手。當然,Google 大神還是要招喚一下。

原來,asp.net mvc 是需要使用 session來作為暫存資料用。(oh! my god)
而我的應用程式的虛擬目錄,是建立在 moss 的網站下,會受到 moss 的 web.config 影響。

參考 http://www.flyvergrillen.dk/2009/03/26/being-trapped-in-iis/ 後,發現雖然我是使用 Windows 2003 ,但發現了我仍是缺少 SessionStateModule ,因此,加上 SessionStateModule,並啟用 SessionState 即可。

<httpModules>
      <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add name="SessionStateModule" type="System.Web.SessionState.SessionStateModule" />
    </httpModules>
    <sessionState mode="InProc" />

MVC (2): Url Routing 的測試

以往,在 Web form 甚至在 asp 的久遠年代,網頁執行的 url 是與作業系統相關的。
舉例來說,http://localhost/app/Bulletin/Add.aspx 這個 url ,我們大概可以猜 add.aspx 是位於 web server 的 c:\wwwroot\inetpub\app\Bulletin\Add.aspx 下。雖然IIS 的網站主目錄會變動,但 Bulletin\Add.aspx 的目錄結構幾乎是定律了。

但,誰說這是一成不變的?在 asp.net 上,也有 HttpContext.Current.RewritePath 方法可以改變執行的網頁。因此上述的定律開始被打破。

到了 MVC 的世界,Url 與執行的網頁是不對應的。Request 必須經由解析後,找到對應的 Controller來處理。由 Request 找到對應 Controller 的過程,就是 url routing。

Url routing 如何配置呢?目前 asp.net mvc 1.0 的做法是在 global.asax.cs 上以 coding 的方法處理。這一點相當不彈性,應該可以在 config file 上設定即可。目前我尚未研究是否有 config file 的方法。

程式如下:

public static void RegisterRoutes(RouteCollection routes)
    {
      routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
      routes.MapRoute(
          "Default",                                              // Route name
          "{controller}/{action}/{id}",                           // URL with parameters
          new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
      );
    }

以上是預設的,也就是 asp.net mcv project template 一開始就建好的範本。

我們也可以寫兩個以上的 routing rule。當 request 進入時,就會由上而下開始對應,直到第一個配對成功。

public static void RegisterRoutes(RouteCollection routes)
    {
      routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
      routes.MapRoute(
    "R1",                                              // Route name
    "Order/{action}/{date}",                           // URL with parameters
    new { controller = "Order", action = "Index", date = "" }  // Parameter defaults
        );

      routes.MapRoute(
          "Default",                                              // Route name
          "{controller}/{action}/{id}",                           // URL with parameters
          new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
      );
    }

此時,http://localhost/app/Order 會match 到 R1 的規則,而其他如 http://localhost/app 的則會被 Default 的規則所補獲。

以上是人工的預測。但這個 routing table 是有些複雜的。到底 match 到哪一個 route卻是相當重要的。有沒有一個工具可以幫我們測試 routing 呢?有的。請參考 http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx  的說明

image

2009年8月28日 星期五

單元測試(2): 單元測試的好與壞

繼上一篇的單元測試(1): 什麼是單元測試

單元測試的寫的好不好,影響執行測試結果的可信任度。

若測試莫名其妙就失敗,難以找到原因,或者錯誤卻不是由自己的受測試程式所造成,而是依賴的其他系統/服務的停止或失敗,測試的可信任度會愈來愈差,沒過多久,就沒有人相信測試的結果。到了最後,就連測試也不執行了。

所以,單元測試要寫好,就是要不相依於其他的服務/系統/程式。

以下舉個例子。

受測的程式
 
using System.IO;

namespace ClassLibrary1
{
  public class Class1
  {
    /// 
    /// 讀取檔案行數
    /// 
    public int CountFileLineNumber(string filePath)
    {
      return File.ReadAllLines(filePath).Length;
    }
  }
}
BAD單元測試
using ClassLibrary1;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace TestProject1
{
  [TestClass()]
  public class Class1Test
  {
    [TestMethod()]
    public void CountFileLineNumberTest()
    {
      Class1 target = new Class1();
      int actual =target.CountFileLineNumber(@"d:\temp\aaa.txt");
      Assert.AreEqual(4, actual);
    }
  }
}
以上的例子是可以正常測試的。那到底什麼地方不好呢?
首先,該測試通常受到版本控管。當別人在他的電腦取得測試後,一旦執行該測試後,通常會失敗。原因:找不到 d:\temp\aaa.txt。
因為該測試必須有 aaa.txt 的輔助才能進行,如果沒有將該檔案一起放到 source control,其他同事進行測試時就會失敗。

再者,別人的電腦, d drive可能是光碟,也可能沒有對應的邏輯磁碟。
這就是「相依於檔案系統」造成的問題。

該怎麼改呢?首先將aaa.txt 加到測試專案中,並且將Copy to Output Directory 的值設為 Copy always。這樣一來,該測試檔案就會跟著專案一起了。

image

再來,將測試程式修改成下方。

using ClassLibrary1;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace TestProject1
{
  [TestClass()]
  public class Class1Test
  {
    [TestMethod()]
    [DeploymentItem("aaa.txt")] <!-- 多這一行 -->
    public void CountFileLineNumberTest()
    {
      Class1 target = new Class1();
      int actual =target.CountFileLineNumber(@"aaa.txt"); <!-- 修改這一行 -->
      Assert.AreEqual(4, actual);
    }
  }
}

DeploymentItem 指名要將 aaa.txt 放到測試目錄一同進行測試,而程式碼在讀取的也會在執行目錄上找檔案。

這樣一來,該「相依於檔案系統」的依賴性就消除了,也就是就更像是「單元測試」了。

Another Mock Framework: Moq

在看單元測試相關的文章後,發現也不少人使用 Moq.

Study 了一下,Ouch! 也相當棒呢!

重點是:非常活躍!看一下release 吧!每個月至少都有三版本 release 呢!

Windows 7 的快速鍵

Windows 7 用了一陣子,實為好物。

而快速鍵呢?記不了這了多,就請到

http://windows.microsoft.com/en-US/Windows7/Keyboard-shortcuts 這裡查囉。

2009年8月25日 星期二

軟體專案的成功率

根據 CHAOS Summary 2009 的報告 (2009 Aug),軟體專案是否成功的比例如下

 

Percentage

succeeding

32%

challenged

44%

failed

24%

 

succeeding: 如期,如質,如預算

challenged:雖然完成了,但時程不如預期,或超支、或刪減需求、或品質不佳等

failed:取消專案,或雖然做完了,卻從不使用。

記得多年前,failed 是 25%, 而 chanllenged 是 51% 吧!總體成功率是上升了,但仍然沒有太大的變化。

2009年8月20日 星期四

單元測試(1): 什麼是單元測試

什麼是單元測試呢?在 Visual Studio 2008 上,在 method 上很簡單,按個右鍵,就可以建立一個單元測試了。如下圖。
image

但是,接下來寫的,就一定是「單元」測試嗎?

類似的問題也發生在物件導向語上。「使用c# 語言開發的程式,一定符合物件導向的程式碼嗎?」

使用c#來寫程式,也需要有物件導向的精神,才能寫出物件導向的程式。這是人為的。
使用Create Unit Tests 的工具來建立單元測試,也必須讓我們寫的測試符合「單元」的精神,才是真的單元測試。

定義

  1. A unit test is a piece of a code (usually a method) that invokes another piece of code and checks the correctness of some assumptions afterward.
  2. If the assumptions turn out to be wrong, the unit test has failed.
  3. A “unit” is a method or function

注意到第3點,unit 所指的測試範圍是一個 method 及 function 的程式碼。

舉例來說,以下的程式碼可以做單元測試,因為沒有涉及其他的程式碼

 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ClassLibrary1
{
  public class MyMath
  {
    public int Add(int a, int b)
    {
      return b + a;
    }
  }
}

但下面的程式碼就不容易做單元測試。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Configuration;
using Microsoft.Practices.Unity;

namespace ClassLibrary1
{
  public class Project
  {
    private ISettings _settings;
    IAuthenticationService _authenticationService;
    public Project(ISettings settings, IAuthenticationService authenticationService)
    {
      this._settings = settings;
      this._authenticationService = authenticationService;
    }

    [Dependency]
    public IWriteLog Logger { get; set; }

    public float GetProjectActualHours(int vProjId, string userName, string pwd)
    {
      if (!_authenticationService.Authenticate(userName, pwd))
      {
        Logger.WriteLog("xxx ");
        throw new NotFiniteNumberException();
      }

      string xmlPath = _settings.XmlPath;
      XElement el = XElement.Load(xmlPath);

      var projectNode = (from e in el.Elements("project")
                         where (int)e.Attribute("ID") == vProjId
                         select e).FirstOrDefault();

      if (projectNode != null)
      {
        var q = (from e in projectNode.Elements("rec")
                 select (float)e.Attribute("Hours")).Sum();
        return q;
      }
      else
      {
        string message = "hello, no projId = " + vProjId;
        return 0;
      }
    }
  }
}

原因呢?當我們在進行GetProjectActualHours 的單元測試時,如果所呼叫的_authenticationService.Authenticate 方法失敗時,應該屬於GetProjectActualHours方法的測試失敗,還是_authenticationService.Authenticate的失敗?

因此,當測試的對象引用到別的程式時,就不容易進行單元測試了。

但是,無論如何,還是可以進行測試。只是,此時的測試不再是「單元」測試了,而是「整合」測試,整合其他的服務/元件進行「整合測試」。或者,「元件測試」的名詞較容易為大家接受

請繼續讀 單元測試(2): 單元測試的好與壞

2009年8月13日 星期四

Windows 7 (x64) 上執行 Visual Studio 2008,執行單元測試時,發生 Code coverage collection error

歡天喜地地安裝完 Windows 7 64 位元版後,就跟著安裝一堆開發用的軟體。
還真的不少。已過了三天,還裝不完呢。

在 Visual Studio 2008 上執行之前的單元測試,全掛了!錯誤原因如下:

Code coverage collection error: The Visual Studio performance and coverage logging engine is already running on the computer. Therefore, the test run cannot continue. Close the pending performance or code coverage session and then rerun the tests.

是什麼意思呢?原來不知為何,Visual Studio 的效能程式 VSPerfMon.exe 無法自行關閉,因此也無法再起一個。

碰到這種情形時,請手動到 task manager 上強制 end process 即可。

2009年8月10日 星期一

Win 7 的安裝

由於之前使用的是 Vista 32bit,這一次想要安裝的是 64 bit. 因此無法直接升級,只好重新安裝了。

安裝的經驗:快!快到我實在驚訝。在家中,忘了計算時間。

今天在公司安裝時,測試一下,只需要 18 分鐘就安裝完成了。

開機、關機、也都比以往快上許多。

2009年8月7日 星期五

Windows 7 終於出來了

最終的版本,終可以可在 MSDN 訂閱下載了。

在颱風夜…

2009年8月3日 星期一

asp.net 的帳號

asp.net 的帳號,有好多個。

其中,最常用的就是 Page.User.Identity,代表使用者登入後,系統認定該使用者的帳號。

這有什麼問題呢?原來,帳號的學問可大著呢。

 protected void Page_Load(object sender, EventArgs e)
    {
      lblPage.Text = this.Page.User.Identity.Name;
      lblThread.Text = Thread.CurrentPrincipal.Identity.Name;
      lblWindowsIdentity.Text = WindowsIdentity.GetCurrent().Name;
      lblLogonUserIdentity.Text = this.Page.Request.LogonUserIdentity.Name;
    }
Identity 說明
this.Page.User.Identity 使用者登入後,系統用來識別該使用者的帳號
Thread.CurrentPrincipal.Identity 這個我不太了解。通常與this.Page.User.Identity相同。
WindowsIdentity.GetCurrent() 代表執行該網頁時,Windows 真正執行的identity
this.Page.Request.LogonUserIdentity IIS 上設定的執行帳號。IIS 6 以後,就是 Application Pool 所指定的identity,通常是 Network Service

這有哪些變化呢?

  1. IIS 上的驗證方式。有 anonymous, windows NTLM。
  2. IIS 上 Application pool 的 identity
  3. web.config 上的 <authenticaion mode=”Forms” or mode=”Window”
  4. web.config 上 <identity impersonate="true", 或 <identity impersonate="true" userName="userName" password="password"/>

這些設定,都可能影響上述4個 identity 的值。由於變化太多了,我也無法完全記錄下來。大家就自行試試看囉!

範例程式下載

2009年8月2日 星期日

patterns & practices Application Architecture Guide 2.0,成為架構師必讀

微軟不斷地提升 .net 的能量,也推出了許多的公開文件。
其中,要讓我們的系統能長長久久地運作下去,好的架構自然是必要選項。

但,系統類型何其多,如 WebForm, WinForm, 甚至 SilverLight,如何作架構設計呢?

patterns & practices Application Architecture Guide 2.0 是您必讀的對象。

2009年7月31日 星期五

Visual Studio Tricks: 建立臨時專案

您是不是和我一樣,常常需要測試一些小程式片斷呢?
常見的例子,如 string.Format(“{0}”, 32.331F) 如何只顯示1位小數,或測試 Regular Express ?

之前,為了測試這些臨時性的專案,也建立了一堆的程式,放到了我的硬碟。
有多少呢?太多了吧,如下圖。

image

這都需要找時間清一清,而且,這已經是努力控制之下的了。

要如何建立臨時專案呢?有兩個步驟。

步驟一:取消 Save new projects when created

在功能表的 Tool/Options,找到如下圖的地方,取消 Save new projects when created 的勾選

image

步驟二:按 Ctrl + Shift +  N

也可以在功能表上選 File/New/Project 啦!。如下圖,注意到此時不會要您選儲存的位置。

image

運作起來與一般的專案並沒有差別。但在儲存 solution 時,會出現如下圖的視窗,要您選位置啦!編號也改成最後的號碼 + 1 了。

image

2009年7月30日 星期四

CodeRush Express

覺得 Visual Studio C# IDE 環境不夠好用嗎?可以試試這個 CodeRush Express.

免費的哦!

2009年7月28日 星期二

Microsoft Visual Studio Tools for the Office System Power Tools v1.0.0.0

開發 Office 2007 的程式,如果是以 xml 的方式來處理文件時, 最為麻煩的一件事,是必須先改名為 .zip 檔,然後解壓,然後再觀察 xml 的 layout,relations。
難道沒有一個好的工具嗎?
有的。

Microsoft Visual Studio Tools for the Office System Power Tools v1.0.0.0

安裝完畢後,打開 Visual Studio 2008,之後直接在檔案總管以拖拉方式拖進 Visual Studio後,就會打開如下圖的視窗。

image

觀察一下 document.xml 吧!這是一個 word 文件的入口。Hello.docx 是一個超簡單的 word 2007 文件,裡面只有一句 Hello,及一個註解「This is good start」

image

打開 document.xml,可看到如下的 xml。看到了 Hello 的文字呢。而且,該段文字是包在一段註解 <w:commentRangeStart w:id=”0” /><w:commentRangeEnd w:id=”0” /> 。

image

而 w:id=”0” 的註解,需參考 comments.xml,如下圖。注意到反白的 <w:comment w:id=”0”  ,就是id=0 的註解。

image

這個小小的範例,可以了解MS2007 的 xml 格式是強大且充滿彈性的。了解了 xml 的格式後,就可以對 office  文件進行自動化的文件產生,對於客戶的需求,又多了一分把握。

2009年7月16日 星期四

IIS LogParser

在調整校能的過程中,除了 VSTS 的 LoadTest 之外,也常常需要分析正式伺服器上的 IIS  Log.
但是,此log為純文字檔,要如何分析呢?我們當然希望匯到資料庫,再以 sql 語法找出想要的資訊。

將IIS Log匯出到資料表的過程,微軟早就出了這樣的工具,LogParser

指令,像下面即可。

"C:\Program Files\Log Parser 2.2\LogParser.exe " "SELECT TO_LOCALTIME(TO_TIMESTAMP([date], [time])) as [createDate], [s-sitename], [s-ip], [cs-method], [cs-uri-stem], [cs-uri-query], [s-port], [cs-username], [c-ip], [cs(User-Agent)], [sc-status], [sc-substatus], [sc-win32-status], [sc-bytes], [cs-bytes], [time-taken] INTO IISLog FROM C:\IISLog\ex090714.log WHERE TO_LOWERCASE (EXTRACT_EXTENSION(cs-uri-stem)) NOT IN ('gif';'jpg';'png';'bmp';'ico';'axd')" -o:SQL -server:serverName -database:IISLog -driver:"SQL Server" -username:userId -password:pwd -createTable:ON -i:W3C

棒吧!連選資料的方式,都像是 sql  語法。

SharePoint Designer 2007 免費了

看來這個不賺錢吧。改成免費了。

http://www.microsoft.com/downloads/details.aspx?displaylang=zh-tw&FamilyID=baa3ad86-bfc1-4bd4-9812-d9e710d44f42

原來2009/04/09 就已經免費了。一直不知道這個消息。

Microsoft ReportViewer 的 Memory Leak 問題

最近,發現當ReportViewer繫結的資料太大時,會發生 Memory leak。也就是吃記憶體,而且不會吐回來。

有圖為證。

圖1:load test 初期,memory 使用量直線上升。

image

圖2:load test 停止後,memory 使用量不會釋放回來。

image

程式也極為簡單,使用了 ReportViewer,  ObjectDataSource。

程式碼可在這裡下載。相關的討論也非常多

2009年7月7日 星期二

軟體專案最重要的技術

在執行軟體專案的過程中,什麼技術是最重要的呢?

UI 的呈現技術嗎?此大類可包括 asp.net WebForm, MVC, Ajax, Silverlight, …等。
商業邏輯實作嗎?此類可包括 enterprise services, transaction, workflow, bpel, BizTalk, ADO.NET Data Service, Web Service, WCF, … 這類真的寫不完,etc.
資料存取技術嗎?此類可包括 Sql server, Oracle, ADO.NET,LINQ to SQL,… 等

每一個技術都需要 study,也有過時的時候。正因為有過時的時候,就不會是「最重要的技術」了。

那我心中最重要的技術是什麼呢?還是回到人類最基本的技巧:溝通。

不會溝通,就沒有辦法與同事共同開發專案,沒辦法良好地表達自己的意見,發表新技術,導入新的SOP。
我曾經有一次經驗,在與客戶討價還價要不要實作一個小功能。討論了20分鐘,決定放棄己見。後來實作加測試這個小功能也是20分鐘左右。

又另一個例子。公司同事利用小技巧,預填了未來的工時,以規避「每日填工時」的困擾,等到一段時間後,再一次調整。這樣的行為,我認為工時會填的不正確,有誰能很精準的在星期五時想起星期一做了哪些事情呢?光這個事情,我又花了兩小時來溝通。

溝通的成本,真的比想像中來得高很多。而且溝通的技巧,不只是在專案上,在朋友、家人都可以用到,不會過時。

所以,溝通技巧,是我認為是「軟體專案最重要的技術」,是最值的投資的事了。

2009年7月3日 星期五

網頁如何在 Enter 鍵被按下時,改成 Tab 鍵 Version 2

上一回,筆者有提到一篇 [Asp.Net] 網頁如何在 Enter 鍵被按下時,改成 Tab 鍵
這一個小技巧的確有效,可是有人提到「如何再加上自動跳下一個 textbox」?

這是什麼意思呢?例如在輸入電話號碼時,格式為 (02)87121298。在設計頁面時,會產生如下畫面。

需求

當輸完 035 後,由於區碼最多三碼,系統應將游標自動跳到下一個 textbox

image

當輸完02後,使用者可以按 Enter 或 Tab 鍵將游標自動跳到下一個 textbox

image

解法

修改上一篇的解法,並加入在 http://wnas.nl/ 找到的 autotab 功能後,修改如下

WebForm1.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication11.WebForm1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="jquery-1.3.2.js" type="text/javascript"></script>
    <script src="autotab.js" type="text/javascript"></script>
</head>
<body>
    <form id="form1" runat="server">
    <div style="vertical-align:middle">
        請輸入電話號碼(<asp:TextBox sam="xxx" ID="TextBox1" runat="server" MaxLength="3" 
            Width="26px"></asp:TextBox>)
        <asp:TextBox sam="xxx" ID="TextBox2" runat="server" MaxLength="8" Width="66px"></asp:TextBox>
    </div>
    </form>
    <script type="text/javascript">
        $(document).ready(
            function() {
                $('input[sam]').autotab();
            }
        );
    </script>
</body>
</html>

autotab.js

jQuery.fn.autotab = function() {
    jQuery(this).keyup(function(e) {
        switch (e.keyCode) {
            // ignore the following keys 
            case 9: // tab
                return false;
            case 16: // shift
                return false;
            case 20: // capslock
                return false;
            default: // any other keyup actions will trigger 
                var maxlength = jQuery(this).attr('maxlength'); // get maxlength value
                var inputlength = jQuery(this).val().length; // get the length of the text
                if (inputlength >= maxlength) { // if the text is equal of more than the max length
                    jQuery(this).nextAll('input[sam]:first').focus(); // set focus to the next text field
                }
        }
    }).keydown(function(e) {
        if (event.keyCode == 13)
            event.keyCode = 9;
        }
    );
}

[Project 2003]如何設定專案在儲存時,自動發佈專案計劃

問題

審核完工時後,我常常只會儲存專案,忘了「共同作業/發佈/專案計劃」。有沒有更簡單的做法?

解答

設定此專案在儲存時,自動發佈專案計劃

步驟

1. 以Project 2003 打開專案,執行「共同作業/共同作業選項」

image

2. 視需要勾選「新增及變更的工作分派」、「專案摘要」、「包含完整專案計劃」後,按確定鍵。

3. 儲存專案

image

2009年7月1日 星期三

使用 MOSS 2007,要 check in 時發生this document was checked out to your local drafts folder but the local copy could not be checked in to the site

天啊!不知道為什麼,取出一個文件後,要存回時竟然發生this document was checked out to your local drafts folder but the local copy could not be checked in to the site。
如下圖。

image

這是怎麼回事?在同一目錄的檔案都正常,唯有這個檔案才這樣,難道是我編輯太久了嗎?

目前我毫無辦法。只能

  1. 保留在C:\Users\charles\Documents\SharePoint Drafts 下的檔案。
  2. 在 MOSS 上將該檔案存回。
  3. 將1步驟的檔案、改個檔名,再 check in 到該 site 上。

就是避開這個檔案。

2009年6月30日 星期二

如何產生原生格式的 Excel 檔?

產生 Excel 的資料檔,是個老需求了。我也寫過一篇產生 Excel 檔的方法,陳述了我所知道的方法。
我最常使用的方法是 Report Service了,但美中不足的是,Report Service 必須將資料一次吃進來。
我所遇到的資料,有200多萬筆,一次吃進來,當然 Out of memory.

因此,我需要一個直接寫 原生格式的 Excel 檔,而非 csv, xml, html 等格式。

那到底什麼是原生格式呢?找到一個微軟開發的文件,

http://download.microsoft.com/download/0/B/E/0BE8BDD7-E5E8-422A-ABFD-4342ED7AD886/Excel97-2007BinaryFileFormat(xls)Specification.pdf,怕了吧,共三百多頁!

也有另一個 Open xml 的文件,http://sc.openoffice.org/excelfileformat.pdf,可惜必須以 office 2003 以上來開啟。我的客戶又是Excel 2002,開不了。

現在,找到了一個 open source 的元件, MyXLS,試用一下,還真的很簡單呢!也可支援中文。

可惜,超傷記憶體,寫出70453 筆資料,產生的過程中就使用了 7xx MB。12萬筆,就 out of memory。(我的開發機器,3GB memory,asp.net 最多可用 1.8GB)

其原理是在 memory 組物件,沒有作 swap 到 harddisk的動作。
這個問題,就像 XmlDocument 超傷記憶體一樣,之後才又出了個 XmlTextWriter

不過,若資料筆數少,則這個 MyXLS 可說是相當好用的了。

如果可以的話,想試試 Open XML Format SDK 2.0, 畢竟是微軟自家的東西,想來會比較好用。但現在仍在 CTP,而且 Excel 2002 開不了。

 

20090702 後記:

後來又找到了 NOPI ,看來比 MyXLS 更節省記憶體(26萬筆, 要864MB),且該元件更新頻率較多。比較建議用這個。

微軟不再全力 support OracleClient

根據微軟 ADO.NET Team 的部落格,System.Data.OracleClient Update 提到他們做了一個決定

The Decision

After carefully considering all the options and talking to our customers, partners, and MVPs it was decided to deprecate OracleClient as a part of our ADO.NET roadmap.

 

意思是說,雖然在 .net 4.0 仍然會支援 OracleClient,但會被標示為deprecated (過時,不被建議),請使用 3rd 的元件。

那我們的因應對策呢?新開發案,請使用 ODP.NET,維護案,就維持原來的狀況即可。

2009年6月29日 星期一

伺服應用程式集區 'DefaultAppPool' 的處理序已意外中止了。處理序識別碼為 '6060'。處理序結束碼為 '0x800703e9'。

客戶那裡一直出現這樣的問題。asp.net 1.1 版的程式升級到 2.0 後,速度出奇的慢。

在事件檢視器上,找到了下面的問題。

  1. 伺服應用程式集區 'DefaultAppPool' 的處理序已意外中止了。處理序識別碼為 '6060'。處理序結束碼為 '0x800703e9'。
  2. 事件類型:    警告
    事件來源:    W3SVC
    事件類別目錄:    無
    事件識別碼:    1011
    日期:        2009/6/29
    時間:        上午 10:03:02
    使用者:        N/A
    電腦:    ComputerName
    描述:
    伺服應用程式集區 'DefaultAppPool' 的處理序與 World Wide Web Publishing 服務通訊時發生嚴重錯誤。處理序識別碼為 '3800'。資料欄位含有錯誤號碼。

    請在 http://go.microsoft.com/fwlink/events.asp 查看說明及支援中心,以取得其他資訊。
    資料:
    0000: 6d 00 07 80               m..€   

 

救命啊!即使我在 asp.net 上已在 global.asax 上,在Application_Error上已做好了寫 exception log 的準備,無奈完全看不到任何的 log ,因為在 IIS 上就掛了,來不及讓 asp.net 來寫出log。

怎麼辦呢?解決過程如下。

  1. 在 C:\WINDOWS\system32\LogFiles\HTTPERR 下找到錯誤訊息。
    2009-06-29 08:15:32 172.16.1.87 56735 172.16.1.64 80 HTTP/1.1 POST /myApp/csharpwrapper/Company.WEB.SystemName.FunctionNAme.ClassName,MyApp.ashx?_method=ServerSideGetProductDummy&_session=rw - 1 Connection_Abandoned_By_AppPool DefaultAppPool
  2. 以'0x800703e9' 在 Bing 上追問題,第二個是微軟 msdn上的說明。微軟的問題,當然找微軟的文件。一看,是 stackOverFlow 的 exception.
  3. 再以 Vistual Studio 2008 在 Windows 2003 上 debug,會發現程式碼一如往常,只是跑完ajax 後,就進入的無限迴圈了。

之前同事在 asp.net 1.1 上為了達到 ajax 的效果,使用了一個 open source 的 ajax library,沒想到升級到 2.0後,會造成如此驚人的效果

解法呢?當然是把元兇換掉,讓正牌的 asp.net ajax 上場囉!

2009年6月27日 星期六

MVC (1): Asp.NET MVC 概念說明

MVC

MVC是一個 UI Presentation Pattern。與三層式架構並無直接關聯。但因為我們也常三層式架構,不可避免的,要如何將 MVC 與三層式架構一起使用呢?首先就必須了解什麼是 MVC.

MVC 是一種展現層(Presentation Layer)的架構。

Model 即資料
View 根據Model的數據,進行內容展示的組件
Controller 接受並處理客戶端的指命(即操作Model),選擇一個View並輸出內容

Asp.net MVC

Asp.net MVC 當然是將 MVC Pattern 使用於  asp.net  上。因此,會多了一些特定的特色。

Model 即資料
View 根據Model的數據,進行內容展示的組件。以 asp.net MVC 來說,就是輸出成HTML。
Controller 接受並處理客戶端的指命(即操作Model),選擇一個View並輸出內容。以asp.net MVC來說,就是負責Page flow or Page logic

Asp.net MVC + 3-layer Application

若加上三層式架構概念後,又加上了下表的粗體字。

Model 即資料。取得資料時,需呼叫業務邏輯層,再呼叫資料邏輯層以存取資料。因此,Model 與業務邏輯層相關性高。
View 根據Model的數據,進行內容展示的組件。以 asp.net MVC 來說,就是輸出成HTML。展示層
Controller 接受並處理客戶端的指命(即操作Model),選擇一個View並輸出內容。以asp.net MVC來說,就是負責Page flow or Page logic,(中文可翻成UI呈現邏輯)。展示層

 

image

相依性

有個非常重要的地方,是 MVC 的相依性,即下圖箭頭的方向。例如,View 相依於 Model,意即 View 組件有參考到  Model 組件。相反地,Model 並不知道 View 的存在。

這樣帶來了一些好處。首先,是同樣的數據(Model)可以使用不同的View來展示出不同的呈現方式。再者,我們可針對有邏輯的部份(Model的商業邏輯,Controller 的UI呈現邏輯)做測試。最難的部份View,即包含網頁的部份,才進行人工測試,如美工編排是否正確等。

image

2009年6月25日 星期四

Visual Studio 2008, Test not excuted

今天初次使用 Rhino Mocks 來進行單元測試時,發生了下面的問題。

image 

從來沒看過這樣的奇景。
再點擊「Test run error」的連結後,發現有下面的錯誤訊息。

Failed to queue test run 'charles@MOSSDEV 2009-06-25 11:27:20': Test Run deployment issue: The location of the file or directory 'c:\qa2009\qa2009\epmosslibtest\bin\debug\Rhino.Mocks.dll' is not trusted.
原來,此 dll 是從網路來的,是被鎖定住的。按下「解除封鎖」鍵
image

之後,重新打開Visual Studio,重新進行測試後才正常了。

2009年6月18日 星期四

在 GAC上的元件,如何以得到 StackTrace infomation?

一般在開發元件時,通常不會選擇放在 GAC。除了 GAC 需要 strong name 及版本號,需要管理外,也有一個常見的問題:放在 GAC 上的元件,若出現 Exception 時,會得不到在 .pdb 檔上的資訊。

那真的沒辦法嗎?今天終於找到答案。

以 command ,進入 c:\windows\assembly 後,dir 一下,得到下面左邊畫面。

image image

此時你會發現,此目錄結構與檔案總管的不同。(右邊)
再深入一些,你就會發現,原來放到 GAC 的元件,是放到這些目錄的。而且,在 GAC_MSIL 目錄下,出現了一堆的元件,其中,我的元件 EPMossLibrary 就在其中了。
進入子目錄後,就會發現,原來同一個元件,可以有不同的版本、公開金鑰,是因為目錄編排的關係。

image

再進子目錄,就是元件放置的地方。使用 GACUtil 或檔案總管來註冊,只會複製 *.dll 檔的。那就自行使用 dos command: copy 來複製元件 pdb 吧!

image

這樣一來, StackTrace 的資料就有行號了。

微軟將釋出免費的防毒軟體 Code name Morro

根據 http://www.networkworld.com/news/2009/061109-microsoft-readies-free-antivirus.html 所述,微軟”很快地”將釋出一個免費的防毒軟體,Code name Morro。
很快?是什麼時候呢?應該是這一兩個月的事。

另外,一旦成了免費的軟體,其他的防毒軟體廠商勢必受到影響。到時難免各家廠商又要宣揚自家軟體的功能、效能、防毒率等,讓吸引消費者掏出錢錢來。

看來一場防毒軟體大戰又要開打。

有沒有其他免費的防毒軟體?有,多的是
但、總沒有微軟的聲勢強。

2009年6月11日 星期四

如何在 Vista 上安裝 Windows SharePoint Service 3.0

這是個老問題了。解答是下面的網址
http://community.bamboosolutions.com/blogs/bambooteamblog/archive/2008/05/21/how-to-install-windows-sharepoint-services-3-0-sp1-on-vista-x64-x86.aspx 

該網址的內容會隨著WSS版本更新,也會不斷的更新、修正內容。

真是佛心來著

[Asp.Net] 網頁如何在 Enter 鍵被按下時,改成 Tab 鍵

客戶原本使用 AS400 的系統,非常習慣輸入後按 Enter 鍵,游標會移到下一個輸入框。
這個在Windows 上是不make sense的。但不管在 WinForm,甚至是 Web Form,都有客戶這樣要求。
原因當然是:讓操作人員在新舊系統上的操作具一致性。

在 Asp.net 上要怎麼做呢?由於此行為已經是 client side 的行為了,與伺服器無器。當然需要借重 jQuery  了.
程式碼如下

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="WebApplication11._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">

    <script src="jquery-1.2.6.js" type="text/javascript"></script>

    <script type="text/javascript">
        $(document).ready(
            function() {
                $('input[hhh=xxx]').keydown(
            function() {
                if (event.keyCode == 13)
                    event.keyCode = 9;
                if (this.value.length == this.maxLength)
                    event.keyCode = 9;
            });
            }
        );
        
    </script>

    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    </asp:ScriptManager>
    <div>
        input 1:<asp:TextBox hhh="xxx" ID="TextBox1" runat="server" MaxLength="8"></asp:TextBox><br />
        input 2:<asp:TextBox hhh="xxx" ID="TextBox2" runat="server"></asp:TextBox><br />
        input 3:<asp:TextBox hhh="xxx" ID="TextBox3" runat="server"></asp:TextBox><br />
        <asp:Button ID="Button1" runat="server" Text="Submit it" UseSubmitBehavior="false" />
    </div>
    </form>
</body>
</html>

重點如下:

  1. function myKeyDown 將 Enter 鍵改成 Tab 鍵,另外,當 text 輸入的長度已達 maxLength 時,也強迫改成 Tab 鍵
  2. 當 document ready 後,將具有 hhh 屬性值為 xxx 的 input ,當 keydown 事件發生時,呼叫  myKeyDown
  3. 之後需要這樣行為的 text box,只需增加 hhh=’xxx’ 的 attribute 即可

Asp.net 4.0 Whitepater

http://www.asp.net/learn/whitepapers/aspnet40/ 

隨手一看,有個新功能是 Auto-Start Web Applications

以往,無論是 jsp or aspx,特色是「第一個 Request」都是啟動程式的 reqeust,都跑的最慢。之後的 reqeust 就不會這麼慢了。

但真的很難說服客服這樣的行為是合理的。有時伺服器為了節省資源,也會自行 showdown application pool 的 process 。
如下圖,預設20分鐘沒有任何的新的 request 後,這個 application pool 的 process 就會被回收 (recyle)。

image

Auto-Start Web Applications 必須跑在 IIS 7.5 (Windows Server 2008 R2)上,可以不必收到第一個 request ,就會自行建立 Process。

這算是一個小的進步吧。

2009年6月9日 星期二

Office 常見 FAQ

根據資料分析,這十篇文章看似簡單,但卻是 Office 基礎使用者最想知道的內容。也歡迎您上去瞧瞧或分享給你的客戶或夥伴。

KB ID

Title

879137

PC 對話 – 如何可以容易及快速地開啟 Word 或 Excel

879152

PC 對話 – 為什麼 Excel 2007 中的數字顯示不正確 ?

879161

PC 對話 – 如何利用 Excel 來完成一些簡單的計算

902991

PC 對話 – 為什麼無法在全新的電腦上找到預先安裝的 Word 和 Excel ?

929630

PC 對話 – 如何在 Office 2007 中讓表格看起來更美觀

942129

PC 對話 – 如何在 Excel 2007 中使用文字藝術師讓文字更美觀

942829

PC 對話 – 如何在 Office 2007 儲存檔案格式為 PDF 格式

954219

PC 對話 – 如何在 Excel 2007 中的圖表新增第二個垂直軸

959355

PC 對話 – 如何在 Office 2007 中使用美工圖案來裝飾你的文件

959356

PC 對話 – 如何在捲動工作表時,讓特定的列與欄固定不動

更多完整內容,請參考進化型知識庫文章大蒐集 http://support.microsoft.com/gp/kbplus/zh-tw

clip_image001

該使用哪一種 Mock Object Framework

在撰寫單元測試時,為了降低相依性,必須自行撰寫 mock, stub 等物件。這樣的工作量太大,又不易維護。

於是 smart people 開始發揮想像力與執行力,創造了許多的 Mock Object Framweork.

這一堆的 framework,該用哪一種好呢?尤其是剛入門的我,當然希望採用最多人用的。

參考 http://weblogs.asp.net/rosherove/archive/2007/04/26/choosing-a-mock-object-framework.aspx,發現投票的結果,Rhino Mocks 是最多人使用的了。

image

2009年6月8日 星期一

亂碼的形成

延伸判斷字串內是否有中文字的話題,有人問到了是否可以判斷亂碼的存在?

我知道亂碼的產生原因有兩種

1. 不知道原有的編碼,而以非原編碼來檢視文件。

例如由判斷字串內是否有中文字例中產生的 all.txt文件 (unicode編碼),以ultraedit 打開來檢視 (會以 ANSI 編碼 打開),就會看到不一樣的文字。

由於這些文字顯示時並非預期的樣子,常常看不懂,俗稱亂碼。

這個文件並非亂碼,只是用錯了編碼來檢視文件。因此只要找到了正確的編碼來檢視即可。

clip_image002 clip_image004

        2. 資料儲存體 (storage) 無法支援編碼。例如 sql datatype varchar(50) 存入了王建煊,因為煊存入後會遺失資料,導致讀出時,煊變成了?。

?或方格等,是指無法顯示的字,因此也是亂碼常見的癥狀。

舉例來說,all2.txt 是 all.txt 以 ANSI 編碼另存來的。在儲存時會出現下面的警告。

clip_image006

強迫儲存後,分別找到 29002 的地方,就會發現 ANSI 的字變成了?

clip_image008clip_image010

再以 UltraEdit 來比較,發現兩邊儲存時的不同。「煊」在unicode 存儲成 4A71,而在 ANSI 只存了 3F。

image image

由於亂碼的形成原因不一,因此也難以判斷進而偵測亂碼的存在。

VS2010 Beta1 在 debug 時超慢?

剛剛在 debug 時,發現在 Virtual PC 2007 SP1 上,VS2010 Beta1 的 debug 效能令人無法忍受,每一次都要等個 10秒左右,才會停在中斷點。
爬了一下文,原來是 historical Debugging 在作崇。
打開 tools/Options, 找到 Historical Debugging, 將之 disabled 掉吧!

image

判斷字串內是否有中文字

這是個老問題了,今天做一個完整的 demo

由於 dotnet framework 內的 string 儲存的是 unicode, 因此我們將字元寫到檔案內,看看哪些字碼是中文字。

      Stream stream = File.Open(@"C:\temp\all.txt", FileMode.Create, FileAccess.Write, FileShare.Read);
      using (StreamWriter sw = new StreamWriter(stream, System.Text.Encoding.Unicode))
        for (int i = 256; i < 65536; i++) sw.WriteLine("{0}:{1}", i, (char)i);

打開 all.txt,發現第一個中文字是 19968 的「一」,最後的中文字是40869的「龥」。

image image

所以呢,所有的中文字都在「一」跟「龥」的範圍之內。
最後,要如何判斷字串內是否有中文字呢?這當然是 regular expression 的工作了。程式碼如下

      Regex ex = new Regex("[一-龥]");
      bool isMatched = ex.IsMatch("jjsss 中文 ksks");  //isMatched will be true

PS: 特別符號,日文等,算不算中文字呢?如果連這些都考慮進來,就有得玩了。跟您的客戶 check 一下吧!

image image

Share with Facebook