2013年3月25日 星期一

project has not been confiured



剛接手一個 VS2010 的專案,想說都是同樣的開發工具所開發的,應該沒什麼問題吧!結果專案一打開,竟跳出個我很陌生的錯誤訊息,然後該專案就無法開啟。

錯誤訊息如下:
The local IIS URL http://localhost/XXX specified for Web project XXX has not been confiured. In order to open this project the virtual directory needs to be configured. Would you like to create the virtual directory now?



從錯誤訊息看起來,是因為這個專案是採用 Web Site 模式開發,但在我的 IIS 裡面找不到相對應的虛擬目錄。原來這專案當初在命名時,可能使用 OOO,但對應的網站虛擬目錄卻是用 XXX,難怪我一開始根據專案名稱來建虛擬目錄時會建錯。

這時候有兩個解決方法,第一個最簡單,就是去更改 IIS 的設定,將 IIS 的虛擬目錄名稱改為 XXX。第二個,則是自己比較陌生的方法,但其實也不難。只要在無法載入的專案上按右鍵,就會出現 Edit OOO.csproj  的選項,點選進去後,會出現一份 xml 格式的設定檔,找到 <IISUrl>,把他註解掉(mark)或改成 http://localhost/XXX ,再重新載入一次專案就可以了。

是不是採用註解 (mark)掉的方式,差別在於:

用註解掉(mark)的方式,程式在執行時,他會透過虛擬一個網站的方式,以 http://localhost:1234/XXX 來呈現。
<!--<IISUrl>http://localhost/XXX</IISUrl>-->

但如果你的 IIS 裡早就已經設定好網站路徑,則可以將 OOO.csproj 裡的 IISUrl 改成正確的位置即可。程式執行實則會是: http://localhost/XXX

參考:The local IIS URL specified for Webproject has not been configured.

2013年3月18日 星期一

Windows 排程無法執行


用 .net 的 console 模式寫了一個 .exe 檔,在自己電腦上直接執行,是正常的,主要功能是讀取同個資料夾下面的 xml 檔,並進行後面的一些處理工作。但奇怪的是,當我使用電腦排程去呼叫 .exe 檔時,就會在排程表裡面發現所建立的排程一直處於「執行中」的狀態,且這個現象一直都不會停止,由於我是設成每天都要執行,所以當第二天的同個時間要執行時,就會出現錯誤,理由是先前的工作尚未結束,所以無法再做新的。這理由我倒覺得合理,但問題是,為何第一天執行的程式遲遲無法結束呢?心裡第一個念頭,是該不會在裡面給我跑無限迴圈吧!!

就在自己含淚一行一行的檢查程式之餘,發現原來程式是停在下面這一行:


System.Console.ReadLine();


原先是我用來判斷是否使用者有正確的擺放 xml 檔到執行程式的資料夾,沒有的話就會跳出訊息,並將執行畫面暫停,等待輸入「Enter」鍵之後再繼續執行。只是這作法,放到 windows 排程裡,就會造成系統為了要等待輸入「Enter」而停在那一直無法結束,其實程式不是在跑無限迴圈,而是無限等待


然而,真正產生問題的原因,並不只是因為自己誤用了 ReadLine()而已,最主要的問題是為何會找不到 xml 檔呢,我用我的兩隻眼睛的確在執行檔的資料夾下面都有看到啊。在網路上有看到許多人在討論 windows 排程無法正常執行的討論議題,其中「Windows server 2008 排程無法執行」這一篇有提到,如果有對檔案進行存取動作時,要使用完整路徑,否則他可能預設會用 C:\Windows\System32 資料夾來處理。我測試了一下,的確如此,假設我是直接去執行 .exe 檔,則他就會以執行檔所在路徑來處理,但使用排程時,就變成 C:\Windows\System32 了。

我在程式裡面有使用到

DataSet dsConfig=new DataSet();
string strFileName="setup.xml";
if(System.IO.File.Exists(strFileName))
{
    dsConfig.ReadXml(strFileName);
}


這寫法很不幸的,在使用 windows 排程時會發生找不到 xml 檔的問題。

於是我改用完整路徑的方法來改善。


首先,透過 GetExecutingAssembly().Location 取得執行檔的完整檔名路徑
System.Reflection.Assembly.GetExecutingAssembly().Location


接著只取執行檔的完整路徑(不含檔名)
Path.GetDirectoryName(FileName)

所以修改後的程式就變成:
DataSet dsConfig=new DataSet();
//取得執行路徑
string strExecPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
//取得 .xml 設定檔完整路徑,windows 排程需使用完整路徑設定
string strFullPath=string.Format("{0}\\{1}",strExecPath,setupFile);


if(System.IO.File.Exists(strFullPath))
{
  dsConfig.ReadXml(strFullPath);
}


原來,將程式改寫為 windows 排程,還需要考慮是否使用「完整路徑」的問題啊!

參考:Windows server 2008 排程無法執行

2012年12月14日 星期五

走到最後還能留在身邊的,都要珍惜

在網路看到一段 Java Code,正想要好好品味一下時,才發現身邊只剩下那台跟著我許多年的 NB,因為他太老了,跑微軟的作業系統更顯吃力,所以才變節投靠 Ubuntu ,早些年前,他身上還貼著正版的微軟 XP 序號、標籤、標語,當年的繁華光景,連「華碩品質堅若石頭」的彩帶我都還留著,如今卻落魄到同我為伍,不經讓我想起「老人與狗」這本書...

我問他,你跑得快嗎?他搖搖頭。
我再問他,你可以跑 Java 嗎?他也搖搖頭。

看到他一臉徬徨無助的眼神,讓我升起悲憫之心,於是我決定好好教他,讓他可以「跑 Java」。


於是,我在深夜裡,冒著外頭的刮風下雪,來到爪哇旗艦店,一進門,就看到親切的業務向我正面迎來,並單手向我熱情的招呼著,同時遞送上來一杯熱騰騰的咖啡。沒多久,我就在展示間看到今年最流行的第七代 Java,型號是七架。望著七架流線的造型,彷彿可以感受到風在我臉上吹拂,速度在我腳下奔馳的快感。我當下就決定買下,並轉送給我的 NB,這種感覺,就好比當年淑珍買積架送給致中的心情是一模一樣的,「天下父母心,花別人的錢最開心」。















印象中,要能夠在 Ubuntu上跑 Java,是要花蠻多功夫的,但我的業務員告訴我一個簡單的方法,叫做 PPA (Personal Package Archive)。只要三行指令,就可以辦到好。

sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java7-installer

原來有一段小故事是這樣的。在 Ubuntu 的世界裡,會有一個叫做「軟體中心」,伴隨著每六個月推出新版本的檔期,都可以在裡面找到最新的套件,而這些套件都是經過 Ubuntu 團隊審核過才放上去的。問題,就在於我們所需要的軟體,是否可以慢慢等待到審核通過後才能使用呢?如果我要的七架已經問世,但又不想等待半年後才拿到,這時就可以使用 PPA  的方式來取得,但風險則是沒通過審核,所以不保證安裝完後是否會影響系統的穩定性。這跟我要買 iPhone 的道理是一樣的,在美國新版的已經問世,但台灣還沒正式開賣,所以只好透過「水貨」的管道來取得。

透過那三行指令,我終於讓我的 NB 可以跑 Java 了,但我發現一個很大的問題,他不認識中文。於是,我又開始「ㄠ」我的業務員,同樣也是得到三行簡單好用的指令來完成中文環境的開發。

# cd /usr/lib/jvm/java-6-sun/jre/lib/fonts
# mkdir fallback
# ln -s /usr/share/fonts/truetype/wqy/wqy-zenhei.ttc

看著他正在努力的奔跑著,我笑了,我睡了....



參考:
01:INSTALL ORACLE JAVA 7 IN UBUNTU VIA PPA REPOSITORY
02:解决ubuntu下java中文字体显示方框问题
03:What Is An Ubuntu PPA & Why Would I Want To Use One?
04:快速添加 Ubuntu PPA 源

2012年12月13日 星期四

與 Split 更親近一點

先前在使用 C# 對字串進行切割 (split) 動作時,常常會希望把空白的字串過濾掉,只留下字串長度不是 0 的。而這工作其實也不難,就是將  split 後所得到的字串陣列,在你要用時用迴圈一筆一筆去濾掉空白的陣列元素。

剛好今天看到 「StringSplitOptions 列舉型別」介紹了其中的「RemoveEmptyEntries」成員,可以限定傳回值不會加入包含了空字串的陣列元素,有這麼好康的事情就來試試效果如何。於是寫了一個簡單的測試程式,沒想到添加了這作法還真是簡潔啊, 而且他從 .net 2.0 就開始支援了。

class Program
{
    static void Main(string[] args)
    {
        string strTest1 = "b,a,c,,";
        char[] charSeprator = new char[] { ',' };

        string strTest2 = "BB[x]CC[x]AA[x]";
        string [] strSeprator=new string[]{"[x]"};

       //以字元來切割
        foreach (string str in strTest1.Split(charSeprator, StringSplitOptions.RemoveEmptyEntries))
            Console.WriteLine(str);

       //以字串來切割
        foreach (string str in strTest2.Split(strSeprator, StringSplitOptions.RemoveEmptyEntries))
            Console.WriteLine(str);

        Console.ReadLine();

    }
}

如果開發環境是.net 3.5以上的版本,還可以更進一步去將 split 的結果進行排序後再取出。例如:

strTest2.Split(strSeprator, StringSplitOptions.RemoveEmptyEntries).OrderBy(g=>g)

就可將陣列進行排序。


參考:
01:StringSplitOptions 列舉型別
02:Extension Methods (C# Programming Guide)

2012年12月11日 星期二

String,StringBuffer,StringBuilder 的三角關係

不管是在 Java 或是 C#,對於 String 這物件應該都不陌生。但如果考量是在字串串接的用途上時, String 的效能可真的就顯得遜色許多。

String 物件一旦在記憶體被配置之後,他就不能夠再改變了,所以他常常被說成是 immutable object。但我們卻很習慣寫成這樣:


三行程式寫完後,請求了三塊新的記憶體配置,也同時浪費了兩塊記憶體。

針對這個問題,Java 提供了 StringBuffer 物件,讓我們可以對字串加加減減,也不會另外再要一塊新的記憶體位址來存放。在這物件當中,Java 還考慮到多執行緒的問題,也就是說,不同的執行緒不會同時對同一個 StringBuffer 物件做新增或是修改的動作,例如當執行緒 A 在使用 「StringBuffer 甲」的時候,執行緒 B 必須等到執行緒 A 完成「StringBuffer 甲」的處理動作 之後才能使用,這就是我們常說的 thread-safe。

對於 Java 所提供的 StringBuffer 物件,針對字串串接的執行校能上,的確可以非常明顯地看到提昇,但一般對程式設計師來說,大部分時機其實可能都不需要考量多執行緒的問題,如果不考慮多執行緒的情況下,減少多餘的判斷處理,是否還有機會再提昇字串串接的效能呢?

果真,在 JDK 1.5. 之後,開始出現了新的物件 StringBuilder ,他與 StringBuffer 的用途幾乎如出一轍,唯一的不同是減少了多執行緒的考量。日後如果只是在寫單一執行緒的程式考量下,StringBuilder 會是較好的選擇。「StringBuffer vs. StringBuilder performance comparison」文章作者Daniel 針對 StringBuilder 與 StringBuffer 兩者間的效能寫了一段簡單的程式來比較,而我自己也透過他的程式在自己電腦上得到了下面數據:


從數據上看來, StringBuilder 已經比 StringBuffer 提昇了一倍以上的效能,當然這兩者更遠遠超過 String 的字串串接。

同樣的情況,也出現在 微軟的 C# 裡。在字串串接的情況下, StringBuilder 遠比 String 的效能提昇很多,唯一讓我不解的,是這次微軟的身上少了 StringBuffer 的味道...,我很認真的想知道這次微軟為何沒收錄 StringBuffer 這物件,但迄今依舊無解。而微軟的 StringBuilder,同樣也是不考慮多執行緒,可以在微軟的官方文件「StringBuilder Class」看到 Thread Safety 的聲明:

Any public static (Shared in Visual Basic) members of this type are thread safe.
Any instance members are not guaranteed to be thread safe.

可從上面申明中知道,C# 裡面的 StringBuilder 並不是 thread-safe。

另一個有趣的地方,是從 JDK 釋出的時程來看看,彷彿 .net 在 2003年時釋出的 .net 1.1, 已經比 Java 更早公佈 StringBuilder 物件了!


經由這一次的整理,可以知道 String 在字串串接上所面臨的效能瓶頸,並透過 Daniel 的程式在定量上可以得到支撐。此外,也可以更清楚去分別依據是否為單一執行緒來正確抉擇 StringBuilder 或 StringBuffer。

參考:
01:StringBuffer vs. StringBuilder performance comparison
02:StringBuilder Class
03:Java JDK (Java Development Kit) Releases Dates and Release Differences
04:Java SE 6全方位學習
05:StringBuilder和StringBuffer的差別及清空內容方式
06:StringBuilder vs StringBuffer
07:Why use StringBuilder? StringBuffer can work with multiple thread as well as one thread?
08:StringBuffer and StringBuilder
09:Is the C# '??' operator thread safe?
10:如何:增進 Visual C# .NET 中的字串串連效能
11:Daniel 簡單測試程式

2012年12月7日 星期五

當 SSRS 遇到 VSS 時應該知道的事

最近接收了一包  SQL Server Reporting Service (SSRS) 所開發的報表,因為這包報表程式沒有使用任何的版本管控。富有正義感且集聚勇氣於一身的我,就當仁不讓地主動請纓要做好版本管控,於是我就用了最簡單的 Visual SourceSafe(VSS) 來控管這包報表。

其實做這事情真的沒有甚麼難度,一下子就把報表全部加到 VSS 裡面去了。但當我一執行報表時,竟然出現:


拒絕存取路徑 'D:\MyCode\bin\Debug\新世代青年生命成長營.rdl'

我想,是不是 「新世代青年生命成長營.rdl」 這隻檔案被設為唯讀所造成的,於是手動去把唯讀取消,再執行一次,結果還是一樣。於是我網路上找了很一陣子,發現有一篇微軟的文章:「修正: 在組建中,清除,伺服器專案錯誤報告,或預覽中 SQL Server 2008 R2 和出價等作業」,原來 SSRS 有 hotfix 啊,於是造著說明去下載,蠻肥的,約2百多M,沒想到更新完後再重試,竟然還是一樣。

在一股不理智的衝動下,我誤刪了 \bin 資料夾。但只要重新佈署一次,這個 \bin 資料夾自己又會重新生出來,且回覆正常了。但過些時日,這問題又會再跑出來一次,我刪除 \bin 資料夾後又可以正常。

當我閱讀了「FISERV TAP - Checking it RDL Source Sets Output Folder to Read Only」,發現這問題在 SSRS 與 VSS 搭配在一起,就很容易發生。解決方法可以參考該篇文章,但我覺得自己最省力氣的,還是刪除 \bin 資料夾。

參考:
01:修正: 在組建中,清除,伺服器專案錯誤報告,或預覽中 SQL Server 2008 R2 和出價等作業
02:FISERV TAP - Checking it RDL Source Sets Output Folder to Read Only
03:Access to the Path Error in Visual Studio
04:修正: 在組建中,清除,伺服器專案錯誤報告,或預覽中 SQL Server 2008 R2 和出價等作業

2012年11月9日 星期五

關於 Reporting Service 的報表資料

不管是使用 SQL Server 的 Business Intelligence Development Studio 或是 Visual Studio 2012 開發 Reporting Service 報表,應該對於報表資料  (Report Data) 這視窗不陌生。


可是,當我不小心按了「X」把他關閉後,卻再也怎麼找不回來了。找了好久才發現,要呼叫他之前竟還要先做一個動作。首先,必須先將專案裡的任何一支報表打開,然後在該報表的設計頁面點一下,主要是讓設計頁面目前是被聚焦(focus)的,這時,再點選最上面功能列裡的「檢視(View)」,在檢視頁籤中,最下面就會出現「報表資料(Report Data)」,點選後就可以找回自己的報表資料視窗了。

關於要在「檢視」功能列中出現「報表資料」選項,還得先點選設計頁面才行的作法,這 UI 的設計邏輯真的會讓人混淆,或許不需這麼複雜,永遠都出現在「檢視」功能列中不就好了嗎?而且加上這限制,還真的想不出有何特別意義。

參考:
01:停駐報表設計師中的報表資料窗格 (SSRS)