เนื่องจากมีบาง NuGet ที่มันมีความพิเศษ แม้ตัว .NET Core / .NET 5++ มันจะใช้ได้แบบ Cross Platform แล้ว แต่มันมี Third Party บางตัว มันจะยังต้องแยกตาม Platform อยู่ครับ ยกตัวอย่าง เช่น IBM DB2 ครับ
แล้วที่นี่ ถ้าเรามีโจทย์/เงื่อนไขประมาณนี้
- ทีม Dev ใช้กันหลากหลาย Platform เช่น Windows / Linux หรือ MacOS จะต้องจูนยังไงให้งานร่วมกันได้
- ตอนส่ง Build ลูกค้าหละ ? จะบิ้วยังไง
Solution
แก้ที่ตัว csproj ของเราครับ โดยเราต้องมาดูกันก่อนว่าตัว cs project มันใส่เงื่อนไขได้ไหม ซึ่งมันทำได้ครับ
- Choose Element (MSBuild) - อันนี้ผมจะใช้แยก Case ในกรณีที่ Build จากตัว Visual Studio กับ จาก Command dotnet build ครับ
- ในเงื่อนไข Build ผมจะให้ดูจากตัว Runtime Identifier ครับ ในส่วน <When> โดยตัว Runtime Identifier จะเป็น Pattern บอก Platfrom (OS) / Version และ Architecture ที่ต้องการนำไปติดตั้ง+ใช้งาน โดย Pattern เหล่านี้ มันจะช่วยให้การ Restore NuGet นั้นง่ายขึ้น แต่ต้องกำหนด NuGet Package ตาม Pattern มันด้วยนะ (ตัว Driver DB2 ไม่น่าจะใช้แล้ว 55) โดย Pattern เช่น linux-x64, ubuntu.14.04-x64, win7-x64, osx.10.12-x64 หรือ mobile อย่าง android.21-arm กับ ios.15-arm64 ก็มีให้ลองนะ
Note
- หากจะดูที่เป็นไปได้ทั้งหมด ดูจากที่นี่เลย runtime/runtime.json at main · dotnet/runtime · GitHub
- ในคำสั่ง dotnet build ถ้าจะส่งตัว Runtime Identifier ให้ดูที่ --r หรือ --os (แบบย่อ) - Case ใช้ command dotnet build เนื่องจาก Runtime Identifier ยังแยกไม่ได้หมด เลยมากำหนด Condition ใน Package Reference ครับ โดยผมจะจับจาก String StartsWith ชื่อ OS ครับ
<When Condition="$(RuntimeIdentifier) != ''"> <ItemGroup> <PackageReference Condition="$(RuntimeIdentifier.StartsWith('win'))" Include="Net.IBM.Data.Db2" Version="6.0.0.300" /> <PackageReference Condition="$(RuntimeIdentifier.StartsWith('linux'))" Include="Net.IBM.Data.Db2-lnx" Version="6.0.0.300" /> <PackageReference Condition="$(RuntimeIdentifier.StartsWith('osx'))" Include="Net.IBM.Data.Db2-osx" Version="6.0.0.300" /> </ItemGroup> </When>
- อย่าลืม Case ของ Visual Studio ด้วย ในส่วน <Otherwise> ตรง Package Reference ผมเลยให้ Condition ไปเรียกใช้งาน bool IsOsPlatform(string platformString) ของ MS Build แต่เท่าที่ให้น้องที่ทำงานลองในส่วนของ Mac มัน return macOS ถ้าดูใน doc จะเป็น OSX
<Otherwise> <ItemGroup> <PackageReference Condition="$([MSBuild]::IsOsPlatform('Windows'))" Include="Net.IBM.Data.Db2" Version="6.0.0.300" /> <PackageReference Condition="$([MSBuild]::IsOsPlatform('Linux'))" Include="Net.IBM.Data.Db2-lnx" Version="6.0.0.300" /> <PackageReference Condition="$([MSBuild]::IsOsPlatform('macOS'))" Include="Net.IBM.Data.Db2-osx" Version="6.0.0.300" /> </ItemGroup> </Otherwise>
- ส่วนสุดท้าย ds.DAO อันนี้ไม่มีเงื่อนไข ในส่วนของ Platform ใช้แบบเดิมได้เลย
<ItemGroup> <PackageReference Include="ds.DAO" Version="2.0.2" /> </ItemGroup>
- ตัว csproj ทั้งหมดครับ
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net6.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <Choose> <When Condition="$(RuntimeIdentifier) != ''"> <ItemGroup> <PackageReference Condition="$(RuntimeIdentifier.StartsWith('win'))" Include="Net.IBM.Data.Db2" Version="6.0.0.300" /> <PackageReference Condition="$(RuntimeIdentifier.StartsWith('linux'))" Include="Net.IBM.Data.Db2-lnx" Version="6.0.0.300" /> <PackageReference Condition="$(RuntimeIdentifier.StartsWith('osx'))" Include="Net.IBM.Data.Db2-osx" Version="6.0.0.300" /> </ItemGroup> </When> <Otherwise> <ItemGroup> <PackageReference Condition="$([MSBuild]::IsOsPlatform('Windows'))" Include="Net.IBM.Data.Db2" Version="6.0.0.300" /> <PackageReference Condition="$([MSBuild]::IsOsPlatform('Linux'))" Include="Net.IBM.Data.Db2-lnx" Version="6.0.0.300" /> <PackageReference Condition="$([MSBuild]::IsOsPlatform('macOS'))" Include="Net.IBM.Data.Db2-osx" Version="6.0.0.300" /> </ItemGroup> </Otherwise> </Choose> <ItemGroup> <PackageReference Include="ds.DAO" Version="2.0.2" /> </ItemGroup> </Project>
อ๋อ แต่การแก้แบบนี้ อาจจะต้องตรวจสอบด้วยนะครับ ว่า NuGet ที่เราเอามาใช้งาน ถ้ามีการขยับ Version อย่าลืมตรวจสอบด้วยนะครับ ว่าทุก Platform หรือ ในส่วนของ Visual Studio กับตัว dotnet build เวอร์ชันสอดคล้องกันไหมครับ
และก็ตอน Build จากระบบ CI/CD อย่างเช่น Jenkins / Gitlab ถ้าจะระบุ Platform ตอน Build ต้องมาปรับ Param ด้วยครับ
- กรณีที่ใช้ dotnet build ส่วน
--os <OS>
dotnet build ds.Invest.WebAPI.csproj --configuration Release -p:Version=${INVEST_SERVICE_VERSION} -p:AssemblyVersion=${INVEST_SERVICE_VERSION} -p:Authors='${COMNAME}' --os ${TARGET_OS} //SAMPLE dotnet build ds.Invest.WebAPI.csproj --configuration Release -p:Version=${INVEST_SERVICE_VERSION} -p:AssemblyVersion=${INVEST_SERVICE_VERSION} -p:Authors='${COMNAME}' --os linux dotnet build ds.Invest.WebAPI.csproj --configuration Release -p:Version=${INVEST_SERVICE_VERSION} -p:AssemblyVersion=${INVEST_SERVICE_VERSION} -p:Authors='${COMNAME}' --os win
- กรณีที่ใช้ dotnet build ส่วน
-r|--runtime
<RUNTIME_IDENTIFIER>
dotnet build ds.Invest.WebAPI.csproj --configuration Release -p:Version=${INVEST_SERVICE_VERSION} -p:AssemblyVersion=${INVEST_SERVICE_VERSION} -p:Authors='${COMNAME}' --r ${TARGET_RUNTIME} //SAMPLE dotnet build ds.Invest.WebAPI.csproj --configuration Release -p:Version=${INVEST_SERVICE_VERSION} -p:AssemblyVersion=${INVEST_SERVICE_VERSION} -p:Authors='${COMNAME}' --r ubuntu.18.04-x64
Reference
- MSBuild property functions bool IsOsPlatform(string platformString)
- MSBuild Conditional Constructs - MSBuild | Microsoft Learn
- OSPlatform Struct (System.Runtime.InteropServices) | Microsoft Learn
- c# - Different NuGet package based on operating system - Stack Overflow
- .NET Runtime Identifier (RID) catalog | Microsoft Learn
Discover more from naiwaen@DebuggingSoft
Subscribe to get the latest posts sent to your email.