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 後,就不會再出現這些惱人的警告了。

2013年3月15日 星期五

WCF Data Services 使用 JSON 格式

好久沒有使用 WCF Data Services 了。

這次 Demo 時,意外發現 WCF Data Services 在 5.3 時(其實更早)已經內建支援 JSON 格式,只是瀏覽器上不太容易試出來。下面,我們就一步步寫出來吧!

STEP1 資料

找一個資料庫吧。我使用 VS2012,隨便開一個 SQL Server (不能是 LocalDB,否則掛在 IIS 上會有問題)。

CREATE TABLE [dbo].[Users](
    [EmpNo] [char](8) NOT NULL,
    [EmpName] [nvarchar](10) NOT NULL,
    [Password] [varchar](64) NOT NULL,
 CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED 
(
    [EmpNo] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

寫入一兩筆料吧。

image

STEP2 EDMX

建立一個Empty ASP.NET application專案(使用 IIS,為了後面Fiddler 能錄到 json 格式)後,再建立一個  ado.net entity model,並且加入剛剛的 Table 作為測試的 Entity Set

image  image

並且,IIS 對應的 Application Pool 先改用 LocalSystem

SNAGHTML56e33f7

 

STEP3 建立 Data Service

建立一個名為 DemoWcfDataService.svc,並且修改對應的程式如下

SNAGHTML548f7d1

public class DemoWcfDataService : DataService<DemoEntities>
{
    public static void InitializeService(DataServiceConfiguration config)
    {
        config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
        config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
    }
}

執行

http://localhost/DS5Service/DemoWcfDataService.svc/Users 

果然是 xml 格式

image

但如果執行 http://localhost/DS5Service/DemoWcfDataService.svc/Users/?$format=json,則會回傳 400 的 http status code,意思就是不支援。

image

STEP4 更新成 DS 5.3

在專案上使用 NuGet,更新成 DS 5.3

SNAGHTML5559799

再執行一下相同的 URL, 就得到了 JSON格式的資料了

image

image

嗯!感覺真好。

STEP5 Client Side

那 Client side 如何取得 json 的資料呢?建立一個 Console Application ,並且 Add Service Reference,如下

SNAGHTML56307aa

程式如下

static void Main(string[] args)
{
    var context = new DemoEntities(new Uri("http://myhost/DS5Service/DemoWcfDataService.svc"));
    var users = context.Users;
    foreach (var user in users)
    Console.WriteLine(user.EmpName);
}

程式可正常執行。但使用的並不是JSON 格式

STEP6 Client 更新成 DS 5.3

SNAGHTML57d15ae

接下來,要將 System.Data.Services.Client 移除,因為這已經被 Microsoft.Data.Services.Client 取代了

image

增加下面兩行程式,說明我們要使用 JSON 格式

context.Format.LoadServiceModel();
            context.Format.UseJson();

image

執行結果竟是:System.NullReferenceException: Object reference not set to an instance of an object.

image

STEP7 安裝 DS Tools 5.3

找到 WCF Data Services 5.3.0 RTM Tools Installer, 先關掉 Visual Studio 2012 後安裝 WcfDataServices.exe。

再打開solution,  刪除舊的 Service Reference,重新執行 STEP5 後,重新執行程式。就正常了 。

image

結論

使用 Fiddler 錄一下 Request / Response,使用JSON 格式的資料遠小於 xml 格式 (253 vs. 2044) 真的省好多哦!

image

Share with Facebook