過去寫過不少 .NET 版本導向的文章,主要處理 ODP.NET 版本相容累積的經驗: (題外話:學會 Managed ODP.NET 後前途有光明一點,但許多老專案仍以 ODP.NET 為主,三不五時要處理版本茶包)

有這麼多經驗撐腰,我自以為是組件繫結導向老手,可以搞定各種狀況... 直到我膝蓋中了兩箭。

在 A 網站做了元件調整,其中需要將 ODP.NET 9207 導向 2.112.1,看了一下 web.config,有加組件繫組導向沒錯: (網站是 ASP.NET 3.5,故加了 MSAJAX System.Web.Extensions 導向內建版本的導向設定)

  <runtime>
    <assemblyBinding>
      <dependentAssembly>
        <assemblyIdentity name="Oracle.DataAccess" publicKeyToken="89B483F429C47342"/>
        <bindingRedirect oldVersion="0.0.0.0-9.9.9.9" newVersion="2.112.4.0"/>
      </dependentAssembly>
    </assemblyBinding>
    <assemblyBinding appliesTo="v2.0.50727" xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35"/>
        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

但實際執行卻會拋出找不到 ODP.NET 9207 的錯誤訊息,同樣做法在另一台測試主機上卻完全沒問題。

比對再比對,測試再測試(我寫了一個 ChkOdpNetVer.aspx 快速檢查,附於下),發現問題出在 runtime 下有兩段 asseblyBinding,ODP.NET 導向所在的第一段少了 xmlns="urn:schemas-microsoft-com:asm.v1",補上導向才會生效。

<%@ Page Language="C#" %>

<script runat="server">
    void Page_Load(object sender, EventArgs e) 
    {
        Response.Write(
            typeof(Oracle.DataAccess.Client.OracleConnection).Assembly.CodeBase);
        Response.End();
    }
</script>

爬到官方文件 - Redirecting Assembly Versions,本草綱目有記確,assemblyBinding 的 xmlns 必須指定為 urn:schemas-microsoft-com:asm.v1。

> To bind an assembly, you must specify the string "urn:schemas-microsoft-com:asm.v1" with the xmlns attribute in the &lt;assemblyBinding&gt; tag.

文章寫好還沒發文,再接獲同事報案,某專案冒出「無法載入檔案或組件'log4net, Version=1.2.10.23127,Culture=neutral,PublicKeyToken=null'或其相依性的其中之一。找到的組件資訊清單定義與組件參考不符。(發生例外狀況於HRESULT: 0x80131040)」,原因是有元件參照了舊版 log4net,但專案由 NuGet 安裝了新版 2.0.8.0,web.config 有設 bindingRedirect,但顯然沒生效。

      <dependentAssembly>
        <assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" curture="neutral"/>
        <bindingRedirect oldVersion="0.0.0.0-2.0.8.0" newVersion="2.0.8.0"/>
      </dependentAssembly>

注意到錯誤訊息 publicKeyToken="null",非強式名稱(Strong Name)組件,而試著將 assemblyIdentity 的 publicKeyToken 改為 null,也沒生效。 最後查到一篇 Stackoverflow 相關討論,提到官方文件有說:

Note You cannot redirect versions for assemblies that are not strong-named. The common language runtime ignores the version for assemblies that are not strong-named.

查詢結果,在.NET 1.1 版 還保留有此一說明,但新版文件已移除,是否某個版本起行為有改不得而知。總之,這次實測結果是我們無法將 publicKeyToken="null" 的 log4net 組件導向新版。

又學了一課,未來遇 bindingRedirect 無效時,先檢查:1. assemblyBinding 的 xmlns="urn:schemas-microsoft-com:asm.v1" 有沒有加? 2. web.config 如果有 <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">,要將 xmlns 拿掉。參考 3. 是否非強式名稱組件(publicKeyToken="null")。

Cases of failed .NET assembly binding redirection caused by missing xmlns attribute and non strong name assembly.


Comments

Be the first to post a comment

Post a comment


90 - 77 =