以為自己MSDTC的處理經驗已夠豐富,不料今天又有新的心得,筆記之。

某台新裝測試主機,多支涉及分散式交易程式冒出「The transaction manager has disabled its support for remote/network transactions.」錯誤,老問題一枚,推測是忘了啟用Network DTC Access。檢查果真漏了啟動選項,啟動後,其中一個ASP.NET網站的分散式交易就正常,但另一個ASP.NET網站下的ASP(對,是ASP不是ASPX,滄海桑田屹立十餘年的阿公級ASP)卻依然噴出系統不支援分散式交易的錯誤訊息:

難道這台機器上只有ASPX才支援分散式交易,ASP不行?不合理!

為了簡化測試及重現問題,把以前寫過的DTC驗證測試改成ASPX程式碼內嵌版分別丟進兩個ASP.NET網站測試:(參考:小密技-在IIS主機現場撰寫測試ASPX偵錯

<%@Page Language="C#"%>
<%@Import Namespace="System.Data" %>
<%@Import Namespace="System.Data.SqlClient" %>
<%@Import Namespace="System.Transactions" %>
<script runat="server">
private void querySqlServer()
{
    string cnStr = "Data Source=server;User Id=user;Password=pwd;";
    cnStr += "Application Name=" + Guid.NewGuid().ToString();
    using (SqlConnection cn = new SqlConnection(cnStr))
    {
        SqlCommand cmd = new SqlCommand("SELECT getdate() as D", cn);
        cn.Open();
        SqlDataReader dr = cmd.ExecuteReader();
        dr.Read();
        Response.Write("<li>" + dr["D"] + "</li>");
        cn.Close();
    }
}
 
void Page_Load(object sender, EventArgs e)
{
   using (TransactionScope tx=new TransactionScope())
   {  
    Response.Write("<ul>");
    querySqlServer();
    querySqlServer();
    Response.Write("<li>" + Transaction.Current.TransactionInformation.LocalIdentifier + "</li>");
    Response.Write("<li>" + Transaction.Current.TransactionInformation.DistributedIdentifier + "</li>");
    Response.Write("</ul>");
    tx.Complete();
   }
}
</script>

執行結果讓人意外,同一支DTCTest.aspx放進ASPX網站執行OK(看到兩組GUID值),丟到ASP所在網站就出現The transaction manager has disabled its support for remote/network transactions.錯誤。同一支程式在同一機器的兩個Web Application傳回不同結果十分吊詭。優先想到是Application Pool設定不同所致,而二者最大差異在於ASP網站被設成Classic模式,而ASP.NET用的則是Integrated,雖然不覺得是關鍵,但總得試試才知。

將ASP網站的AppPool改成Integrated,但因不相容網站壞掉無法測試,只能再改回Classic,無意間再跑一次DTCTest.aspx,發現分散式交易已正常~

事後推敲,應是Classic改Integrated的過程重啟了AppPool,分散式交易支援才生效,但為什麼ASPX網站不需要重啟就能生效仍待研究。總之,為此修訂設定MSDTC之SOP,納入「設定後要IISRESET」以避免類似狀況再次發生。


Comments

# by supershowwei

asp 環境的怪問題真的都讓人驚豔。

# by Gelis

我猜,會有這樣的差異是因為 IIS 的 Integrated AppPool 採用的是多行程隔離(Process Isolation) 方式啟動,而 Classes AppPool 採用的相容 IIS6.0以前的 ISAPI 來啟動 Handler,而這之間最大的差異在於,記憶體與狀態管理的模式不同,過去ISAPI和現有的大部分Win32 API一樣會自動配置緩衝區,這也是過去ISAPI容易發生錯誤的原因。IIS7.0新的 Integrated 整合模式的所有API則都由伺服器管理記憶體,所以不用重新啟動即可生效。

# by Jeffrey

to Gelis, 這個推測蠻合理的,感謝補充。

Post a comment