【茶包射手日記】ASP.NET 2.0 Web Site 升 3.5 怪異問題一則
4 |
分享在同事專案發現的有趣茶包。
同事接手超古老的 ASP.NET 2.0 WebSite 專案,第一步先升級成 3.5,從青銅器時代推演到鐵器時代。依過去經驗,3.5 也基於 2.0,除了要將 AJAX 擴充功能轉成內建,幾乎是無痛升級。(事實上,2.0 就算升 4.0/4.5 也很少遇到麻煩)
但這回遇上怪事。未升 3.5 前 Build Web Site 成功,升級後出現缺少 ASP.NET AJAX Toolkit 版本問題, 排除過程冒出一個編譯錯誤,某個共用類別存取了外部程式庫元件的 internal 屬性。程式寫法挺妙的,舉例來說,元件 CommLib.Data.DataHelper 有個內部屬性 connString,Web Site 裡的共用類別為了要存取它,故意把自己的 namespace 也改成 CommLib.Data,假裝跟程式庫成為一家人,彷彿這樣就可以存取到 internal 屬性! 依我所知,internal 限制同一組件內存取,要開放限制需由 internal 一方主動宣告(參考:【笨問題】紅杏出牆的internal類別),將 namespace 取一樣就想變自己人,跟改姓就能繼承遺產一樣天真。
但事實擺在眼前,原本 2.0 Build Web Site 是成功的,改成 3.5 才出錯,莫非 2.0 跟 3.5 行為不同? 3.5 底層仍是 2.0,不夠有此差異。取來專案,逐步剔除無關程式反覆測試,當搞清楚是怎麼一回事,我差點笑了出來~
首先,跨組件存取 internal 成員這事兒從頭到尾都是不可行的,不管在 2.0 還是 3.5 都是編譯錯誤。那 Build Web Site 可以成功又是怎麼一回事?後來我才注意到,這顆亂來的共用類別被誤放在網站專案的根目錄下,依據 Web Site 規則,不屬於任何 ASPX、ASCX 的共用程式應放在 App_Code 才能被編譯及引用,換言之,這個問題共用類別根本是一段沒用到的有錯廢 Code。推測還有一種可能,該 internal 屬性更早前曾被宣告為 public,但在 Web Site 根目錄放共用程式純屬白忙一場(幹這種傻事還會被 Visual Studio 警告,如下圖),編譯不到也用不了,至於為什麼專案會留著這段廢 Code 則是謎。
雖然 Build Web Site 會忽略放在根目錄下的共用類別,但如果在 Visual Studio 開啟它,Error List 倒是會忠實指出錯誤。所以,先前的怪現象是這麼來的 - .NET 2.0 時 Build Web Site 成功時沒開啟問題類別,升 3.5 後於修正過程在 IDE 開啟此一存取 internal 屬性類別,Error List 報錯,而我們誤判這是升 3.5 導致的問題(其實問題一直都在,只是先用沒用 VS2017 開啟它就眼不見為淨)。搞清楚這點,先前無法解釋「升 3.5 出錯後再降回 2.0 錯誤也不會消失」現象也有了合理解釋 - 有沒有錯誤要看你有沒有在 VS 開啟它,跟 2.0/3.5 無關。
用一段展示重演狀況,我故意在 Web Site 根目錄下放了一個 BadClass.cs,裡面有一段無厘頭程式碼 BadClass Bad Bad Bad;,確保此類別絕對無法被編譯。而如操作所示,一開始 Build Web Site 成功,Error List 無錯誤,開啟 BadClass.cs 後,Error List 出現三項錯誤,Solution Explorer 跟 BadClass.cs 冒出紅蚯蚓,但 Build Web Site 依舊是成功的!
真相大白,學到 Web Site 編譯行為的冷知識,收工~
A website project which could build and run successfully showing errors under Visual Studio IDE. It ended up with a buggy and unused global class was put incorrectly under website's root.
Comments
# by 唯
您好,借這篇問一下 不曉得您有沒有遇過這樣的問題,我在 .cs 裡面寫了個 getToken() 的 function (return string) 然後在 .aspx 的 head 裡面插入這樣的程式碼 <meta name="gis1Token" content="<%= getToken() %>" /> 結果他居然變成 <meta name="gis1Token" content="<%= getToken() %>" /> 但是我只要把那個 function 改成有參數的假設是 getToken(dynamic _) 然後這樣用 <meta name="gis1Token" content="<%= getToken("") %>" /> 他就會很正常地執行並且回傳結果… 我搜尋了老半天找不到解決方法,想請問您有沒有什麼解決方案,謝謝 orz
# by 唯
哦對了我的 C# 版本是開 4.5.2
# by Jeffrey
to 唯,我有成功重現你描述的問題(還試出參數傳null、123、'A'都不行,要出現雙引號才可以。我個人覺得算是WebForm解析<%=...%>語法的Bug,Stackoverflow https://stackoverflow.com/a/8107519/288936 上有一些解法你可以參考看看,其中<%= "" + GetToken() %>是我覺得較簡單的Workaround。
# by 唯
to Jeffery: 原來我下錯關鍵字難怪都沒看到我要的 XD 你試的我也都試過,而且很奇妙的是這只有在 <head> 裡面才會發生 orz 看來前面先加個雙引號的解法比較快 冏