昨天分享 .NET 4.5.2 專案參照 4.6.1 專案,只有警告訊息但編譯會出錯的茶包,靠將 A 專案升為 4.6.1+ 解決,但愈想愈不對...

若低版本 .NET 參照高版本註定無法運作,為什麼被歸為警告而非錯誤?而 .NET 4.X 採「就地更新」(In-Place Update)政策,在安裝 .NET 4.8 的環境, 以 .NET 4.0、4.5、4.6、4.7、4.8 為目標編譯的程式都是在 .NET 4.8 版 Runtime 執行,故 .NET 低版本專案參照及呼叫 .NET 高版本 DLL,理論上是可行。除非 .NET 4.8 編譯的程式被丟到 .NET 4.6.1 的環境跑又呼叫了 .NET 4.7+ 才有的新功能才會出錯,所以這個不一定會出錯的問題是警告而非錯誤。

為了驗證,我假設一個情境,讓 .NET 4.6.2 網站專案參照 .NET 4.8 程式庫專案,部署到安裝 .NET 4.8 的主機,檢測其是否能正常執行。若是,那低版參照高版僅視為警告而非錯誤就有合理的解釋。(補充:.NET 4.X - 到 .NET 4.6.1 到 2022/4/26 已全數 EOS 了,專案仍可編譯及使用,確認執行環境有升級到 4.6.2+ 即可,參考:.NET Framework 技術支援終止期限(EOS)整理檢查 .NET Framework 4.5+ 版本是否需要升級)

在開始前,先溫習 .NET 4.X 版本升級的基本知識(推薦 MVP Rick Strahl 這篇好文:.NET 4.5 is an in-place replacement for .NET 4.0)。

簡單來說,.NET 4.5 安裝時會覆寫換掉 \Windows\.NET Framework\V4.0.30319 的 .NET 4 舊版 dll,沿用相同目錄同樣檔名,置換成新版本。因此,安裝 .NET 4.5 後,即使是以 .NET 4 為目標編譯的程式,使用的也會是 .NET 4.5 版 Runtime 及系統組件。而 .NET 4.5.X、4.6.X、4.7.X、4.8 的升級也是依循相同模式。如下圖,我的電腦已安裝 .NET 4.8,V4.0.30319\System.dll 的版號便是 4.8.4488.0。

因此,依理推論在 .NET 4.6.2 網站呼叫 .NET 4.8 程式庫是可行的,即使動用 .NET 4.7 或 4.8 才有的新功能,依然可行。

我建了兩個專案實地驗證,MyWeb 設成 .NET 4.6.2,程式庫 Net48Lib 則以 .NET 4.8 編譯:

測試 .NET 4.7+ 新 API 部分則用 HttpClientHandler.SslProtocols 屬性,它是 4.7.1 才新加的屬性。

    public class Net47Funcs
    {
        public static string TestHttpClientNewApi()
        {
            var hch = new HttpClientHandler()
            {
                SslProtocols = SslProtocols.Tls12
            };
            return hch.SslProtocols.ToString();
        }
    }

如昨天所說,在正常狀況下,Visual Studio 會因參照對象 .NET 版本較高無法編譯:

爬文找到一個密技,修改 csproj 加上 <SpecificVersion>false</SpecificVersion> 可以克服版本過高無法編譯問題:
(初步研究原理,似乎是 SpecificVersion = true 會允許編譯程序在找不到組件時繼續進行,但純屬猜測。參考來源 Stackoverflow Interestingly enough, the build then continues! If the code has no actual references to the assembly, the build succeeds (with the previously mentioned warning). )

  <ItemGroup>
    <ProjectReference Include="..\Net48Lib\Net48Lib.csproj">
      <Project>{92a072b6-c588-43c8-88e8-d3b3560e877f}</Project>
      <Name>Net48Lib</Name>
      <SpecificVersion>true</SpecificVersion>
    </ProjectReference>
  </ItemGroup>

修改後,警告仍在,但網站已可成功編譯。

    public class HomeController : Controller
    {
        // GET: Home
        public ActionResult Index()
        {
            return Content(BasicFuncs.GetGuid());
        }

        public ActionResult Net47NewApi()
        {
            return Content(Net47Funcs.TestHttpClientNewApi());
        }
    }

實測,以 .NET 4.6.2 編譯的 MVC 網站,執行 .NET 4.7.1 才有的 HttpClientHandler.SslProtocols 相關程式,測試成功! 證明只要執行環境 .NET 版本較新,.NET 4.X 專案參照 .NET 較高版本 DLL 是可行的!

就醬,再學到一些冷知識!

Experiment to prove .NET 4.6.2 project referencing .NET 4.8 library can run on .NET 4.8 environment.


Comments

Be the first to post a comment

Post a comment