Làm cách nào để bạn đa mục tiêu một thư viện lớp .NET Core với csproj?


94

Khi .NET Core vẫn sử dụng project.jsonđịnh dạng này, bạn có thể xây dựng một thư viện lớp nhắm mục tiêu nhiều khung (ví dụ: net451, netcoreapp1.0).

Bây giờ định dạng dự án chính thức đang csprojsử dụng MSBuild, làm cách nào để bạn chỉ định nhiều khuôn khổ để nhắm mục tiêu? Tôi cố gắng để tìm kiếm này từ các thiết lập dự án trong VS2017, nhưng tôi có thể chỉ nhắm mục tiêu một khung duy nhất từ các khuôn khổ NET Core (nó thậm chí không liệt kê .NET Framework đầy đủ các phiên bản khác mà tôi làm đã được cài đặt) :

nhập mô tả hình ảnh ở đây


Đó không phải là những gì nó phải trông như thế nào, bạn phải lấy các lựa chọn .NETStandard 1.x được liệt kê trong menu thả xuống. Không rõ điều này xảy ra như thế nào, hãy đảm bảo chọn đúng mẫu dự án để bắt đầu. Phải là "Thư viện Lớp (Tiêu chuẩn .NET)". Có vẻ như bạn đã chọn mẫu Ứng dụng Console và sau đó bắt đầu thay đổi thuộc tính, không phải theo cách chính xác. Nếu trên thực tế, bạn đã sử dụng mẫu Thư viện Lớp thì quá trình cài đặt không diễn ra tốt đẹp.
Hans Passant

Tôi thực sự đã chọn Thư viện lớp (.NET Core).
Gigi

2
Đúng, đó là sai nếu bạn muốn đa mục tiêu. Bạn phải chọn .NETStandard để làm cho thư viện có thể sử dụng được trên nhiều nền tảng.
Hans Passant

Điều đó xóa nó. Bạn có thể viết câu trả lời từ nhận xét của mình nếu bạn thích.
Gigi

Câu trả lời:


119

Bạn cần phải chỉnh sửa thủ công tệp dự án và thêm s vào TargetFramework mặc định và về cơ bản thay đổi nó thành TargetFrameworks . Sau đó, bạn đề cập đến Moniker với một ;dải phân cách.

Ngoài ra, bạn có thể đặt các tham chiếu gói Nuget trong một ItemGroup có điều kiện theo cách thủ công hoặc sử dụng VS Nuget Package Manager.

Đây là giao diện .csproj của bạn:

<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>

Một cách giải quyết khác mà tôi thực hiện những ngày này vì thiếu tài liệu là tôi tạo một dự án trong VS2015 và hình thành project.json bằng cách sử dụng tài liệu có sẵn và intellisense, sau đó mở giải pháp trong VS2017 và sử dụng bản nâng cấp tích hợp sẵn. Sau đó, tôi sẽ xem xét tệp csproj để tìm cách thực hiện cấu hình đó.

Nhắm mục tiêu nhiều mục tiêu bí truyền hơn mà không có Moniker :

Microsoft:

PCL không được khuyến nghị +

Mặc dù PCL được hỗ trợ, các tác giả gói nên hỗ trợ net tiêu chuẩn thay thế. Tiêu chuẩn nền tảng .NET là sự phát triển của PCL và thể hiện khả năng di động nhị phân trên các nền tảng bằng cách sử dụng một biệt danh duy nhất không gắn với biệt danh tĩnh như portable-a + b + c.

Nếu bạn muốn nhắm mục tiêu một xách tay hồ sơ nó không có một định nghĩa trước biệt danh rất Profiles xách tay cũng không thể suy luận TargetFrameworkIdentifier, TargetFrameworkVersionTargetFrameworkProfile . Ngoài ra, một hằng số biên dịch không được định nghĩa tự động. Cuối cùng, bạn phải thêm tất cả các tham chiếu lắp ráp không được cung cấp theo mặc định.

Ví dụ bên dưới này được lấy từ một dự án đã sử dụng dynamictừ khóa, vì vậy nó cũng cần thêm phần hợp Microsoft.CSharpngữ, do đó bạn có thể thấy cách nó tham chiếu cho các mục tiêu khác nhau.

<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
Bạn phải thực hiện việc này bằng cách chỉnh sửa csproj theo cách thủ công hay có thể thực hiện thông qua VS?
Gigi

1
@Gigi đa nhắm mục tiêu cần được thực hiện theo cách thủ công. Các gói Nuget có thể được thực hiện thông qua VS2017 hoặc thủ công.
Aboo

2
Tôi đang gặp vấn đề tương tự và mọi thứ đều hoạt động tốt sau khi tôi thêm các s vào <TargetFramework>. Thực sự ước những điều này được ghi lại tốt hơn.
Negorath

2
@AsadSaeeduddin có khả năng là Resharper đang hiển thị cho bạn những tiếng kêu rắc rối chứ không phải Visual Studio. $ (TargetFramework) chỉ được sử dụng để cung cấp một ItemGroup cho một khuôn khổ / Moniker cụ thể.
Aboo

2
@ORMapper nếu gói NuGet được xây dựng chính xác, điều này sẽ tự động xảy ra khi bạn nhập. Có nghĩa là nếu NuGetPackageA đã hỗ trợ nhiều khung công tác, bạn không cần phải đặt nó vào một nhóm mục có điều kiện. Bây giờ nếu bạn cần tham chiếu PackageA cho khung .net và PackageB cho lõi .net thì điều đó cần được đặt trong nhóm mục có điều kiện. Không có tùy chọn nào trong giao diện kể từ hôm nay (tháng 10 năm 2017).
Aboo

24

Bạn có thể chỉnh sửa thủ công .csprojtệp cho thuộc tính này và đặt TargetFrameworks(not TargetFramework).

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

Ví dụ EFCore.csproj: xem : https://github.com/aspnet/EntityFrameworkCore/blob/951e4826a38ad5499b9b3ec6645e47c825fa842a/src/EFCore/EFCore.csproj


9
Cảm ơn! Nó giết tôi. Trong cuốn "Các yếu tố của phong cách lập trình" của Brian Kernigan được viết cách đây 4 thập kỷ, ông nói về những sai lầm khi sử dụng các biến chỉ khác một chữ cái ở cuối. Sẽ rõ ràng hơn rất nhiều nếu tên là "TargetFrameworkList".
howardlo

Ví dụ mà bạn chỉ vào không bao gồm thuộc tính <TargetFrameworks>.
RenniePet

@RenniePet, cảm ơn bạn! Tệp dự án đã thay đổi theo thời gian. Tôi đã thay đổi liên kết thành một cam kết cụ thể, trong đó có <TargetFrameworks>.
Người đi bộ đêm vào

12

Tôi thực sự đã chọn Thư viện lớp (.NET Core).

Đó không phải là mẫu dự án bạn muốn nếu thư viện của bạn cần hoạt động trên nhiều mục tiêu nền tảng. Với mẫu dự án này, thư viện của bạn chỉ có thể được sử dụng trong một dự án nhắm mục tiêu .NETCore. Phương pháp tiếp cận thư viện PCL đã ngừng hoạt động, bây giờ bạn phải chọn .NETStandard.

Bạn làm như vậy bằng cách bắt đầu dự án với mẫu dự án "Thư viện lớp (.NET Standard)". Bây giờ bạn có tùy chọn chọn phiên bản .NETStandard. Lưới tương thích hiện tại là ở đây .

Hy vọng rằng họ sẽ cập nhật bài viết được liên kết đó. Đây là trong dòng chảy, .NETStandard 2.0 đã được đóng đinh nhưng chưa xuất xưởng. Được đặt mục tiêu cho quý 2 năm 2017, có thể là vào cuối mùa xuân, hiện tại nó cho thấy là đã hoàn thành 97%. Tôi tình cờ nghe các nhà thiết kế nói rằng không nên sử dụng 1.5 hoặc 1.6, không đủ tương thích với 2.0


Nó hoạt động như thế nào nếu bạn có các phụ thuộc khác nhau cho các khung mục tiêu khác nhau? Ý tôi là project.jsonbạn có thể chỉ định các phụ thuộc cụ thể cho khung mục tiêu.
Gigi

1
Tôi chắc chắn 90% rằng bạn cần phải quên rằng điều này đã từng tồn tại. Đó là một mớ hỗn độn khó hiểu mà chỉ là một biện pháp ngăn cách cho bootstrap .NETCore. Sử dụng lưới tương thích mà tôi đã liên kết.
Hans Passant

Tôi đã nghi ngờ nhiều như vậy. Cảm ơn rất nhiều vì đã làm rõ!
Gigi

4
@HansPassant multi-target vẫn là lựa chọn tốt nhất nếu bạn có mã kế thừa và đồng thời việc phát triển greenfield của bạn có thể được thực hiện bằng một trong các phiên bản khung mới đầy đủ hoặc dotnetcore.
Stefano Ricciardi

1
Ngay cả greenfield cũng không nhất thiết phải thân thiện với .NET Core. Tôi đang sử dụng Ứng dụng chức năng Azure nhưng phiên bản .NET Core của họ chỉ hỗ trợ một vài trình kích hoạt. (Tôi cần kích hoạt Service Bus, vì vậy tôi đang bị mắc kẹt với .NET Framework và một thư viện chức năng kinh doanh rất lớn có thể trở thành đa mục tiêu.) Nền tảng của Microsoft hiện đang là một mớ hỗn độn. Nó tương đương với DLL Hell hiện đại.
McGuireV10

5

Tôi đã thực hiện một hướng dẫn cho người mới bắt đầu về khung lưới đa mục tiêu và netcore bắt đầu với bản sửa lỗi 1 dòng đơn giản và sau đó hướng dẫn bạn qua từng biến chứng.

Cách tiếp cận đơn giản nhất là làm cho một mục tiêu netcore hoặc net tiêu chuẩn hoạt động trước. Sau đó, chỉnh sửa tệp csproj và thực hiện các bước này cho các mục tiêu khác.

  1. Tìm hiểu về các phần có điều kiện trong tệp csproj của bạn để bạn có thể khai báo các phần phụ thuộc khác nhau cho từng mục tiêu. Tạo các phần có điều kiện cho mỗi mục tiêu.
  2. Thêm <Reference />scho Hệ thống. * Dlls cho bất kỳ mục tiêu netframework nào chỉ bằng cách đọc thông báo lỗi xây dựng cho biết bị thiếu.
  3. Xử lý các phần phụ thuộc NuGet <PackageReference />strong trường hợp chúng không giống nhau cho từng mục tiêu. Mẹo đơn giản nhất là tạm thời hoàn nguyên về nhắm mục tiêu đơn lẻ để GUI sẽ xử lý các tham chiếu Nuget một cách chính xác cho bạn.
  4. Đối phó với mã không biên dịch trên tất cả các mục tiêu, bằng cách học nhiều kỹ thuật, cách giải quyết và tiết kiệm thời gian sáng tạo.
  5. Biết khi nào nên cắt lỗ khi chi phí thêm nhiều mục tiêu quá cao.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.