คุณกำหนดเป้าหมายไลบรารีคลาส. NET Core หลายเป้าหมายด้วย csproj ได้อย่างไร


96

เมื่อ. NET Core ยังคงใช้project.jsonรูปแบบคุณสามารถสร้างไลบรารีคลาสที่กำหนดเป้าหมายหลายเฟรมเวิร์ก (เช่น net451, netcoreapp1.0)

ตอนนี้รูปแบบโครงการอย่างเป็นทางการกำลังcsprojใช้ MSBuild คุณจะระบุกรอบงานหลายรายการเพื่อกำหนดเป้าหมายได้อย่างไร? ฉันพยายามที่จะมองหานี้จากการตั้งค่าโครงการใน VS2017 แต่ฉันสามารถที่จะกำหนดเป้าหมายเฉพาะกรอบเดียวจากกรอบ .NET หลัก (มันไม่ได้มีรายการอื่น ๆ รุ่น .NET Framework เต็มรูปแบบซึ่งผมไม่ได้ติดตั้ง) :

ป้อนคำอธิบายภาพที่นี่


นั่นไม่ใช่สิ่งที่ควรจะเป็นคุณควรได้รับตัวเลือก. NETStandard 1.x ที่แสดงในเมนูแบบเลื่อนลง ยังไม่ชัดเจนว่าเกิดขึ้นได้อย่างไรโปรดเลือกเทมเพลตโครงการที่เหมาะสมเพื่อเริ่มต้น ควรเป็น "Class Library (.NET Standard)" ดูเหมือนว่าคุณเลือกเทมเพลต Console App แล้วเริ่มเปลี่ยนคุณสมบัติไม่ใช่วิธีที่ถูกต้อง หากคุณใช้เทมเพลตไลบรารีคลาสแล้วการติดตั้งทำได้ไม่ดี
Hans Passant

จริงๆแล้วฉันเลือก Class Library (.NET Core)
Gigi

2
ถูกต้องนั่นคือสิ่งที่ผิดถ้าคุณต้องการหลายเป้าหมาย คุณต้องเลือก. NETStandard เพื่อให้ไลบรารีใช้งานได้บนแพลตฟอร์มมากกว่าหนึ่งแพลตฟอร์ม
Hans Passant

นั่นเป็นการล้างมัน คุณสามารถเขียนคำตอบจากความคิดเห็นของคุณได้หากต้องการ
Gigi

คำตอบ:


122

คุณจำเป็นต้องแก้ไขด้วยตนเองแฟ้มโครงการและเพิ่มsเริ่มต้นtargetFrameworkและพื้นเปลี่ยนเป็นTargetFrameworks จากนั้นคุณพูดถึงMonikerด้วย; ตัวคั่น

นอกจากนี้คุณสามารถใส่การอ้างอิงแพ็คเกจ Nuget ใน ItemGroup แบบมีเงื่อนไขด้วยตนเองหรือใช้ VS Nuget Package Manager

นี่คือลักษณะของ. csproj ของคุณ:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>netstandard1.6;net452</TargetFrameworks>
  </PropertyGroup>

  <ItemGroup Condition="'$(TargetFramework)' == 'net452'">
    <PackageReference Include="Microsoft.Azure.DocumentDB">
      <Version>1.12.0</Version>
    </PackageReference>
  </ItemGroup>

  <ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.6'">
    <PackageReference Include="Microsoft.Azure.DocumentDB.Core">
    <Version>1.1.0</Version>
    </PackageReference>
  </ItemGroup>
</Project>

วิธีแก้ปัญหาอื่นที่ฉันทำในวันนี้เนื่องจากเอกสารขาดหายไปคือฉันสร้างโครงการใน VS2015 และสร้างโครงการ json โดยใช้เอกสารที่มีอยู่และ Intellisense จากนั้นเปิดโซลูชันใน VS2017 และใช้การอัปเกรดในตัว จากนั้นฉันจะดูไฟล์ csproj เพื่อหาวิธีทำให้การกำหนดค่านั้นเกิดขึ้น

การกำหนดเป้าหมายหลายเป้าหมายที่ลึกลับมากขึ้นโดยไม่ต้องใช้Moniker :

ไมโครซอฟต์:

ไม่แนะนำ PCL

แม้ว่า PCL จะได้รับการสนับสนุน แต่ผู้เขียนแพ็กเกจควรสนับสนุน netstandard แทน NET Platform Standard เป็นวิวัฒนาการของ PCL และแสดงถึงความสามารถในการพกพาแบบไบนารีข้ามแพลตฟอร์มโดยใช้ชื่อเล่นเดียวที่ไม่ได้เชื่อมโยงกับรูปแบบคงที่เช่นแบบพกพา -A + b + c

หากคุณต้องการที่จะกำหนดเป้าหมายส่วนตัวแบบพกพาก็ไม่ได้มีการกำหนดไว้ล่วงหน้าชื่อเล่นดังนั้นโปรไฟล์แบบพกพานอกจากนี้ยังไม่สามารถสรุปTargetFrameworkIdentifier, และTargetFrameworkVersion TargetFrameworkProfileยังไม่ได้กำหนดค่าคงที่ของคอมไพเลอร์โดยอัตโนมัติ ในที่สุดคุณต้องเพิ่มการอ้างอิงแอสเซมบลีทั้งหมดไม่มีให้ตามค่าเริ่มต้น

ตัวอย่างด้านล่างนี้นำมาจากโปรเจ็กต์ที่ใช้dynamicคีย์เวิร์ดดังนั้นจึงจำเป็นต้องมีMicrosoft.CSharpแอสเซมบลีเพิ่มเติมดังนั้นคุณจะเห็นว่ามันอ้างอิงสำหรับเป้าหมายต่างๆอย่างไร

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>netstandard1.5;net40;portable40-net45+sl5+win8+wp8</TargetFrameworks>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetFramework)'=='portable40-net45+sl5+win8+wp8'">
    <TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier>
    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
    <TargetFrameworkProfile>Profile158</TargetFrameworkProfile>
    <DefineConstants>$(DefineConstants);PORTABLE158</DefineConstants>
  </PropertyGroup>

  <ItemGroup Condition="'$(TargetFramework)'=='netstandard1.5'">
    <PackageReference Include="Microsoft.CSharp" Version="4.3.0" />
    <PackageReference Include="System.ComponentModel" Version="4.3.0" />
  </ItemGroup>

  <ItemGroup Condition="'$(TargetFramework)'=='net40'">
    <Reference Include="Microsoft.CSharp" />
  </ItemGroup>

  <ItemGroup Condition="'$(TargetFramework)'=='portable40-net45+sl5+win8+wp8'">
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System" />
    <Reference Include="System.Core" />
    <Reference Include="System.Windows" />
  </ItemGroup>
</Project>

1
ต้องทำเองโดยแก้ไข csproj เองหรือจะทำผ่าน VS ก็ได้?
Gigi

1
@Gigi หลายการกำหนดเป้าหมายต้องทำด้วยตนเอง แพ็คเกจ Nuget สามารถทำได้ผ่าน VS2017 หรือด้วยตนเอง
Aboo

2
ฉันประสบปัญหาเดียวกันและทุกอย่างทำงานได้ดีหลังจากที่ฉันเพิ่ม s ใน <TargetFramework> หวังเป็นอย่างยิ่งว่าสิ่งเหล่านี้ได้รับการบันทึกไว้ดีกว่า
Negorath

2
@AsadSaeeduddin มีโอกาสที่ Resharper จะแสดงให้คุณเห็น squiggles ไม่ใช่ Visual Studio $ (TargetFramework) ใช้เพื่อทำให้ ItemGroup พร้อมใช้งานสำหรับเฟรมเวิร์กเฉพาะ / Moniker
Aboo

2
@ORMapper หากแพ็คเกจ NuGet สร้างขึ้นอย่างถูกต้องสิ่งนี้จะเกิดขึ้นโดยอัตโนมัติเมื่อคุณนำเข้า หมายความว่าถ้า NuGetPackageA รองรับหลายเฟรมเวิร์กแล้วคุณไม่จำเป็นต้องวางไว้ในกลุ่มไอเท็มที่มีเงื่อนไข ตอนนี้ถ้าคุณต้องการอ้างอิง PackageA สำหรับ. net framework และ PackageB สำหรับ. net core แล้วจะต้องใส่ในกลุ่มรายการที่มีเงื่อนไข ไม่มีตัวเลือกในอินเทอร์เฟซ ณ วันนี้ (ต.ค. 2017)
Aboo

24

คุณสามารถแก้ไข.csprojไฟล์สำหรับสิ่งนี้และตั้งค่าคุณสมบัติTargetFrameworks(ไม่ใช่TargetFramework) ได้ด้วยตนเอง

<TargetFrameworks>net451;netstandard1.4</TargetFrameworks>

ดูตัวอย่างEFCore.csproj: https://github.com/aspnet/EntityFrameworkCore/blob/951e4826a38ad5499b9b3ec6645e47c825fa842a/src/EFCore/EFCore.csproj


9
ขอบคุณ! มันฆ่าฉัน ใน "The Elements of Programming Style" ของ Brian Kernigan ที่เขียนไว้เมื่อสี่ทศวรรษก่อนเขาพูดถึงข้อผิดพลาดของการใช้ตัวแปรที่แตกต่างกันโดยใช้ตัวอักษรตัวเดียวในตอนท้าย มันจะชัดเจนกว่านี้มากถ้าชื่อคือ "TargetFrameworkList"
howardlo

ตัวอย่างที่คุณชี้ไปไม่มีคุณสมบัติ <TargetFrameworks>
RenniePet

@RenniePet ขอบคุณ! ไฟล์โครงการมีการเปลี่ยนแปลงตามเวลา ฉันเปลี่ยนลิงค์เป็นการคอมมิตคอนกรีตโดยมี <TargetFrameworks>
Night walker

12

จริงๆแล้วฉันเลือก Class Library (.NET Core)

นั่นไม่ใช่เทมเพลตโครงการที่คุณต้องการหากไลบรารีของคุณต้องทำงานกับเป้าหมายหลายแพลตฟอร์ม ด้วยเทมเพลตโปรเจ็กต์นี้ไลบรารีของคุณสามารถใช้ได้ในโปรเจ็กต์ที่กำหนดเป้าหมาย. NETCore เท่านั้น วิธีการไลบรารี PCL ถูกยกเลิกตอนนี้คุณต้องเลือก. NETStandard

คุณทำได้โดยเริ่มโปรเจ็กต์ด้วยเทมเพลตโปรเจ็กต์ "Class Library (.NET Standard)" ตอนนี้คุณมีตัวเลือกในการเลือกเวอร์ชัน. NETStandard ตารางการทำงานร่วมกันในปัจจุบันอยู่ที่นี่

หวังว่าพวกเขาจะอัปเดตบทความที่เชื่อมโยงนั้นอยู่เสมอ สิ่งนี้อยู่ในฟลักซ์. NETStandard 2.0 ถูกตอกลง แต่ยังไม่ได้จัดส่ง ตั้งเป้าไว้ในไตรมาสที่ 2 ของปี 2017 ซึ่งอาจเป็นช่วงปลายฤดูใบไม้ผลิซึ่งขณะนี้แสดงให้เห็นว่าทำได้ 97% ฉันได้ยินนักออกแบบบอกว่าไม่แนะนำให้ใช้ 1.5 หรือ 1.6 ไม่เข้ากันได้กับ 2.0


จะทำงานอย่างไรหากคุณมีการอ้างอิงที่แตกต่างกันสำหรับกรอบเป้าหมายที่แตกต่างกัน? ฉันหมายความว่าproject.jsonคุณสามารถระบุการอ้างอิงเฉพาะสำหรับกรอบเป้าหมาย
Gigi

1
ฉันมั่นใจ 90% ว่าคุณต้องลืมว่าสิ่งนี้เคยมีอยู่จริง มันเป็นความยุ่งเหยิงที่สับสนซึ่งเป็นเพียงมาตรการหยุดช่องว่างของ bootstrap .NETCore ใช้ตารางความเข้ากันได้ที่ฉันเชื่อมโยง
Hans Passant

ฉันสงสัยพอ ๆ ขอบคุณมากสำหรับการชี้แจง!
Gigi

4
@HansPassant หลายเป้าหมายยังคงเป็นตัวเลือกที่ดีที่สุดหากคุณมีรหัสเดิมและในขณะเดียวกันการพัฒนากรีนฟิลด์ของคุณก็สามารถทำได้ในรูปแบบเต็มเฟรมเวิร์กหรือ dotnetcore ล่าสุด
Stefano Ricciardi

1
แม้แต่กรีนฟิลด์ก็จำเป็นต้องเป็น. NET Core ที่เป็นมิตร ฉันใช้แอปฟังก์ชัน Azure แต่เวอร์ชัน. NET Core รองรับทริกเกอร์สองสามตัวเท่านั้น (ฉันต้องการทริกเกอร์ Service Bus ดังนั้นฉันจึงติดอยู่กับ. NET Framework และไลบรารีการทำงานทางธุรกิจที่มีขนาดใหญ่มากอาจจะกลายเป็นหลายเป้าหมาย) แพลตฟอร์มของ Microsoft ยุ่งเหยิงในตอนนี้ มันเทียบเท่ากับ DLL Hell ที่ทันสมัย
McGuireV10

5

ฉันได้ทำคู่มือสำหรับผู้เริ่มต้นเกี่ยวกับ net framework และ netcore แบบหลายเป้าหมายซึ่งเริ่มต้นด้วยการแก้ไข 1 บรรทัดง่ายๆจากนั้นจะแนะนำคุณเกี่ยวกับภาวะแทรกซ้อนแต่ละอย่าง

วิธีที่ง่ายที่สุดคือการทำให้ netcore หรือ netstandard target ทำงานก่อน จากนั้นแก้ไขไฟล์ csproj และทำตามขั้นตอนเหล่านี้สำหรับเป้าหมายอื่น ๆ

  1. เรียนรู้เกี่ยวกับส่วนเงื่อนไขในไฟล์ csproj ของคุณเพื่อให้คุณสามารถประกาศการอ้างอิงที่แตกต่างกันสำหรับแต่ละเป้าหมาย สร้างส่วนที่มีเงื่อนไขสำหรับแต่ละเป้าหมาย
  2. เพิ่ม<Reference />sสำหรับ System. * dlls สำหรับเป้าหมาย netframework ใด ๆ เพียงแค่อ่านสิ่งที่ข้อความแสดงข้อผิดพลาดของบิลด์บอกว่าขาดหายไป
  3. จัดการกับ NuGet dependencies <PackageReference />sในกรณีที่แต่ละเป้าหมายไม่เหมือนกัน เคล็ดลับที่ง่ายที่สุดคือเปลี่ยนกลับเป็นการกำหนดเป้าหมายครั้งเดียวชั่วคราวเพื่อให้ GUI จัดการการอ้างอิง Nuget ให้คุณได้อย่างถูกต้อง
  4. จัดการกับโค้ดที่ไม่ได้รวบรวมในทุกเป้าหมายด้วยการเรียนรู้เทคนิควิธีแก้ปัญหาและการประหยัดเวลาที่หลากหลาย
  5. รู้ว่าเมื่อใดควรลดการสูญเสียของคุณเมื่อต้นทุนในการเพิ่มเป้าหมายสูงเกินไป
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.