某天,我在維護正式機的 ASP.NET WebForm 系統(EIP)時,發現一件奇怪的事:
kgeip\bin\x64\SQLite.Interop.dll
的修改時間居然是 2024/10/29,但它卻能正常運作。對照本機打包時的 DLL(版本為 2025/6/30),代表我 Build 完根本沒有正確覆蓋到正式機的版本。
原本以為是小事,沒想到這背後踩了好幾個坑。
在處理一個 ASP.NET Web Site 專案(不是 Web Application)時,我遇到錯誤訊息:
System.DllNotFoundException: 無法載入 DLL 'SQLite.Interop.dll':找不到指定的模組
這讓我重新面對一個老問題:非託管 DLL(native DLL)在 WebForm 專案中的管理與部署問題。特別是這些 DLL 來自 NuGet 時,還原機制比預期複雜很多。
我的 packages.config
指定版本如下:
<package id="System.Data.SQLite" version="1.0.113.6" />
<package id="System.Data.SQLite.Core" version="1.0.113.6" />
<package id="System.Data.SQLite.Linq" version="1.0.113.6" />
這些會還原出:
類型 | 描述 |
---|---|
System.Data.SQLite.dll | .NET 託管 DLL |
SQLite.Interop.dll | Native C++ DLL(需依平台複製) |
但問題是,SQLite.Interop.dll 並不會自動複製進 /bin
。
我原以為執行 nuget restore
就夠,實際卻不是:
指令 | 功能 |
---|---|
nuget restore |
還原套件到 /packages |
Update-Package -Reinstall |
強制將 DLL 安裝至 /bin 並更新 web.config |
這點在 WebSite 專案特別重要,因為 NuGet 並不會自動處理 native DLL 複製。
我加進 build.bat
的處理:
:: 建立 bin 子資料夾
if not exist kgeip\bin\x64 mkdir kgeip\bin\x64
if not exist kgeip\bin\x86 mkdir kgeip\bin\x86
:: 搜尋並複製 SQLite.Interop.dll
for /R %%I in (SQLite.Interop.dll) do (
echo %%~dpI | findstr /I "\\x64\\" >nul && (
copy /Y "%%~I" kgeip\bin\x64\ >nul
)
echo %%~dpI | findstr /I "\\x86\\" >nul && (
copy /Y "%%~I" kgeip\bin\x86\ >nul
)
)
搭配 web.config 的 probing 設定:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="bin\x64;bin\x86"/>
</assemblyBinding>
</runtime>
這樣就能在執行期自動載入對應平台的 DLL。
即使還原了套件,只要 /bin
被清空,會立刻遇到以下錯誤:
System.IO.FileNotFoundException: 找不到 System.Data.SQLite.dll
System.DllNotFoundException: 無法載入 SQLite.Interop.dll
只有 Update-Package -Reinstall
能正確還原這些 DLL 到 /bin
,並處理相依關係。
環境 | 建議做法 |
---|---|
開發機 | 用套件管理器,定期 Reinstall |
正式機(WebSite) | 手動複製 DLL,搭配 bat 維護 native DLL |
正式機(WebApp) | 可用 MSBuild 搭配 .csproj 自動處理 |
修改完 bat、重建完專案後,我打算 pull 最新的主線代碼,卻報錯:
Unable to pull when changes are present on your branch.
我先執行:
git restore kgeip/Bin/EDAPortal.dll
正常。
但當我想還原 Interop 檔案時:
git restore kgeip/Bin/x86/SQLite.Interop.dll
卻報錯:
error: unable to unlink old 'kgeip/Bin/x86/SQLite.Interop.dll': Invalid argument
我停用 IIS 才成功解除鎖定。
我重新整理 build.bat
,加入以下功能:
msbuild.exe
kgeip.sln
kgeip\bin
我希望能 commit SQLite.Interop.dll
,就加入:
!kgeip/Bin/x86/
!kgeip/Bin/x86/SQLite.Interop.dll
並強制加入:
git add -f kgeip/Bin/x86/SQLite.Interop.dll
讓 git 忽略整個 bin 的同時,仍能追蹤這個重要 DLL。