2013年9月4日 星期三

AnyCPU, x86, x64, ARM

今天終於稍微了解了 AnyCPU的用意了。特地記錄下來,避免記憶體 reset 的老問題。

Visual Studio.NET 2003

在這個年代之前,並沒有64位元的 CPU(應該說不普及)。此時 Visual Studio 並不提供 CPU 相關的選項。回想一下,這是多麼美好的事。

Visual Studio 2005,2008

也才再過個兩年,64 位元的 CPU 開始在伺服器上普遍了起來。到了2007年前後,連桌上電腦也愈來愈普及。為了面對問題,微軟 Visual Studio 2005 開始有了 AnyCPU 的平台目標選項。

image

那到底使用 AnyCPU 的 assembly 會如何的被地行呢?此時的決策是非常簡單,而且看來也十分有效:

當 assembly 使用的是 AnyCPU 平台目標時,且

  • 執行在 32 位元Windows作業系統時,會以 32 位元的方式執行,IL 會被編譯成 x86 的 native code。
  • 執行在 64 位元Windows作業系統時,會以 64 位元的方式執行,IL 會被編譯成 x64 的 native code。

問題

由於目前的64位元電腦 (Windows) 都是32位元相容的,因此一個 assembly 在64位元的電腦只能以 64 位元的方式來執行,恐怕不妙。我常碰到的例子是 Oracle Client。

當我們的存取 Oracle 資料庫的程式以 AnyCPU 編譯後,執行在 64 位元的電腦,會以 64 位元的方式來執行。但如果安裝的 Oracle Client 是32位元的呢?32 位元的 Oracle Client 載入 64 位元的程式,就會拋出 System.BadImageFormatException 例外。

Visual Studio 2010

上面的問題持續了3~4年,到底 32 位元與 64位元應用程式好壞也漸漸地有了較明確的選擇。

除非明確地需要大量的記憶體,或者需要長整數,否則32位元就已經足夠。64位元的效能還會有一些些下降。

因此,在 Visual Studio 2010,建立新專案時,Target Platform(平台目標) 預設就是 x86。
但是,AnyCPU 的assembly 執行方式仍然沒有變。

Visual Studio 2012

到了 Visual Studio 2012又有變化。這個時間點,正巧 ARM CPU (也是32bits)也要進來,因此 32bit === x86 時代正式終結。

Visual Studio 2012 建立新專案後的預設選項為 AnyCPU32BitPreferred。
注意一下, Prefer 32-bit 被 disable 掉,是指不能修改,但在.NET Framework 4.5 就可以設定了!

image

當 assembly 使用的是 AnyCPU 平台目標時,且

  • 執行在 32 位元Windows作業系統時,會以 32 位元的方式執行,IL 會被編譯成 x86 的 native code。
  • 執行在 64 位元Windows作業系統時,會以 64 位元的方式執行,IL 會被編譯成 x64 的 native code。
  • 執行在 ARM Windows作業系統時,會以 32 位元的方式執行,IL 會被編譯成 ARM 的 native code。

因此,Perfer 32-bit 可以說是特地為 ARM 設計的。

結論

AnyCPU 從一開始,到目前其定義仍然沒有變動過。也就是「碰到ppp的作業系統,就執行成ppp的程式」,其中 ppp 可以是 32bit, 64bit, ARM。

改變的是「建立專案時的預設選項」。

也因此,上述 Oracle Client 的問題還是很可能會發生。建議儘可能地明確地指定平台目標(Target Platform),以減少不確定性。

2013年6月14日 星期五

System.Transactions 裡的 Timeouts 與 Azure 中的設定

在進行交易的過程中,主要有三個 Timeout 時間。而真正的可交易時間,是取下面三者的最小值。

Command.CommandTimeout

這個 timeout 是最基本的 Timeout 時間,預設為 30 秒。這個設定是執行sql指令的可執行時間。

TransactionScope 的Timeout

在執行交易時,TransactionScope 也有一個 Timeout 時間。這個時間是由 TransactionScope 的建構子中的參數來指定的。預設值是60秒,可由 TransactionManager.DefaultTimeout 取得設定值。

TransactionManager 的  MaximumTimeout

TransactionManager 裡頭也有一個 timeout。這個 timeout 時間是是全機的交易管理員的最大可交易的時間。在 .NET 2.0 預設可由子層的 config 或程式來覆寫。但在 .NET 4.0,就不能被子層來覆寫了,如果需要修改,則必須到 %windir%\Microsoft.NET\Framework\v4.0.30319\Config\machine.config (32 位元),或 %windir%\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config 中以管理員的權限進行修改。

<system.transactions>
    <machineSettings maxTimeout="02:00:00" />
</system.transactions>

Azure 中設定

微軟的 Windows Azure Cloud Service 環境中,當然我們可以使用遠端桌面的方式,連線到每個伺服器進行上述的修改。但是一旦重新掛載作業系統後,這些人工設定又全部跑掉必須重設,非常不人道。幸好部署時有 Start Task 的機制, 可以執行 cmd 的指令。cmd 指令如下

windir%\system32\inetsrv\appcmd set config /commit:MACHINE /clr:4 -section:machineSettings -maxTimeout:02:00:00

此指令必須寫成 .cmd 檔,放在 WebRole 或 WorkerRole 的 project 內,以 content/Always copy to Output Directory 的型式加入專案

image   image

接著,在Azure 專案的 ServiceDefinition.csdef 中加上 Startup Task 的指令

<Startup>
  <Task commandLine="timeout.cmd" executionContext="elevated" taskType="simple" />
</Startup>

如下圖

image

其中 executeContext=”elevated” 指的是必須以管理員的權限進行修改

結論

TransactionScope 的 Timeout 設定有點複雜,除了.NET 版本,32/64 版本,%windir%\system32\ 與 %windir%\SysWOW64\ 的不同外,現在又增加了雲端的設定。真是不太容易。

參考

  1. http://stackoverflow.com/questions/1348191/default-transaction-timeout
  2. https://github.com/Aaronontheweb/azure-webroleperformance-scripts
  3. http://blogs.inkeysolutions.com/2012/01/managing-timeouts-while-using.html

2013年6月13日 星期四

jQuery 取得 checkbox 至少有一個選取

客戶的需求中,「當使用者至少要選取一筆資料才能進行下一個動作」。常見的 UI 設計,當然是使用 checkbox。

而我的 case,是資料有一萬多筆,此時整個網頁非常痴肥而難以接受。問題是,客戶就是要這樣的網頁,客戶拒絕分頁

jQuery length

問題來了,此時我使用了如下的 jQuery 語法查詢是否有選取一個 checkbox

var isChecked = $('input[name=chk]:checked').length > 0;

相當然爾,網頁就硬生生當在那裡,動也不能動。效能不好

jQuery is

根據我「多年」「 .NET」的經驗,使用 length 等同於計算所有被勾選的項目,然後再計算出總筆數,這樣的效能當然不好啊。於是趕快找一找 jQuery document,很快的就發現了 jQuery is 非常符合我的需求。於是馬上改了程式

   1: var isChecked = $('input[name=chk]')is(':checked');

滿心期待效能飛快,但「更慢了」。怎麼會…

效能比較

找到一個測試,也證實了這樣的結果。怎麼會這樣…

另外,又找了一個 checkboxtests,這次加入了自己寫的 .each() 來測試是否會比較快?結論是:不會。

心得

到了 javascript 的世界,以前許多經驗值就必須大打折扣了。

2013年6月3日 星期一

將 Visual Studio 打包好的 package 佈署到 IIS 6

之前的許多經驗,都是把打包好的 package 佈署到 IIS 7 以上的版本。此中又依據權限,再分成管理員權限的佈署及非管理員權限的佈署方式

這次,我被要求佈署到 IIS 6 上了。

IIS 6

我之前的態度,是一味地以「Windows Server 2003 大舊了,現在沒有人在用了」來推託一翻。雖然言之有理,但其是一大部份原因是:懶!
然而,債還是要還的。客戶出錢,我們做人家小的還是要出力,即使入不敷出。

IIS 6 與之後的 IIS 7有個根本上的不同,是IIS 7 對 metabase 的全面改版,並且 IIS 7 可支援非管理員來管理 IIS。在 Visual Studio 發行的結果,是對 Web Deploy 是再包裝過精簡後的工具,處理的對象是  IIS 7 的 metabase。對於 IIS 6,只能自行尋找文件。

如果直接使用 Visual Studio 所產出的 cmd 指令執行到 IIS 6,會出現如下的錯誤訊息。

SNAGHTML243900aa

使用 MSDeployAgentService

在同一個目錄中,可以找到 Visual Studio 為我們寫好的 readme 檔案,其實裡面已經寫的很清楚了,是可以使用這些工具部署到 IIS 6的。

The service URL can also be in the following format:
        http://<DestinationServer>/MSDeployAgentService 
    This format requires administrative rights on the destination server, and it requires that Web Deploy Remote Service (MsDepSvc) be installed on the destination server. IIS 7 does not have to be installed on the destination server.

也就是說, 我們必須使用 http://serverName/MSDeployAgentService 使用管理員權限來進行部署。

改一下指令,如下

package.cmd /T /M:http://localhost/MSDeploymentService

結果不如人願,非常類似的錯誤訊息還是打擊了我一下。

SNAGHTML2429b1de

解法

注意到了問題了嗎?另一個重點在於 Metabase 路徑,新舊版本不一樣。所以,我偷偷修改了SetParameters.xml,由原來的

<setParameter name="IIS Web Application Name" value="Default Web Site/myApp" />

改成

<setParameter name="IIS Web Application Name" value="/lm/w3svc/1/ROOT/myApp" />

再執行相同的指令

package.cmd /T /M:http://localhost/MSDeploymentService

就完成了我的需求了。

其實,如果是在本機的話,指定機器的 /M 指令也不用加了。只需要

package.cmd /T 即可

進階

由於使用了 MSDeploymentService,就必須使用管理員的權限。既然是管理員權限,在別台機器(只需要安裝 Web Deploy Tool)當然也可以下指令,不必遠端桌面登入到該伺服器。

package.cmd /Y /M:http://serverIpOrHostName/msdeployagentService /U:administrator /P:Password

PS: 對部署來說,這個權限要求實在大到不行,對於無限上綱的資訊安全管理說,就是很好發揮的題材。誰叫你還要用 Windows Server 2003 呢?

2013年5月10日 星期五

IE8 與 Knockout js

客戶抱怨網頁呈現不正確。資料出不來。

看了一下,客戶使用的是 IE8 on Windows 7。天啊!算很新的系統,但就是不肯更新 IE 版本。

問題在 Knockoutjs

我用IE 10 按F12 開發者工具,檢查一下錯誤的 javascript

image

SCRIPT5022: Unable to parse bindings.
Message: SyntaxError: Expected identifier, string or number;
Bindings value: text: CompanyName, attr: { for: 'c' + TaxNo()}

binding 的 html 如下

<label data-bind="attr:{for: 'r' + ReportHeaderId()}, text: ReportName"></label>

原因

舊版本IE 會將 for: 當成 javascript 的保留字,想把它當成 javascript 來跑,因而錯誤。

解法

加上單引號,變成字串即可

<label data-bind="attr:{'for': 'r' + ReportHeaderId()}, text: ReportName"></label>

2013年5月8日 星期三

There was a mismatch between the processor architecture of the project being built "MSIL" and the processor architecture of the reference

問題

使用Visual Studio 2012 建置專案時,出現了如下的錯誤

Warning    6    There was a mismatch between the processor architecture of the project being built "MSIL" and the processor architecture of the reference "msshrtmi, Version=1.8.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=AMD64", "AMD64". This mismatch may cause runtime failures. Please consider changing the targeted processor architecture of your project through the Configuration Manager so as to align the processor architectures between your project and references, or take a dependency on references with a processor architecture that matches the targeted processor architecture of your project.   

原因

我在這個專案使用了 Windows Azure的雲端 assembly msshrtmi,並且指定了 x64的版本。但在建置的設定上,卻指定為 Any CPU。雖然編譯會過,但一定要部署到 x64 的作業系統才能正常運作。

在 .NET 4.5 後 ,編譯會多出這樣的警告。

解決

一直出現這樣的警告實在很惱人。把該專案的 Platform target 設成 x64 就解決了這個問題

image

解決 TFS Build 時 出現 C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets (983) 的警告

問題

當我在 Team Foundation Server 上佇列一個新的組建後,組鍵的結果常常跑出一堆的警告。如下

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets (983): The reference assemblies for framework ".NETFramework,Version=v4.5" were not found. To resolve this, install the SDK or Targeting Pack for this framework version or retarget your application to a version of the framework for which you have the SDK or Targeting Pack installed. Note that assemblies will be resolved from the Global Assembly Cache (GAC) and will be used in place of reference assemblies. Therefore your assembly may not be correctly targeted for the framework you intend.

不處理,好像也沒什麼事。只是,一直覺得怪怪的。

解法

原來,雖然我在 Build Server 上有安裝了 .NET Framework V4.5, 可以順利的建置,仍然會出現上述的警告。在Build Server 上安裝  Windows Software Development Kit (SDK) for Windows 8 後,就不會再出現這些惱人的警告了。

Share with Facebook