Як багатоцільово націлити бібліотеку класів .NET Core за допомогою csproj?


94

Коли .NET Core все ще використовував project.jsonформат, ви можете створити бібліотеку класів, націлену на декілька фреймворків (наприклад, net451, netcoreapp1.0).

Тепер, коли в офіційному форматі проекту csprojвикористовується MSBuild, як ви визначаєте декілька фреймворків для націлювання? Я намагаюся шукати це в настройках проекту в VS2017, але я можу тільки цільової єдину структуру з рамок .NET ядра (вона навіть не перелічити інші повні версії .NET Framework , які я дійсно встановили) :

введіть тут опис зображення


Це не так, як це повинно виглядати, вам слід отримати варіанти .NETStandard 1.x, перелічені у спадному меню. Не дуже зрозуміло, як це сталося, обов’язково виберіть правильний шаблон проекту, щоб розпочати. Має бути "Бібліотека класів (.NET Standard)". Схоже, ви вибрали шаблон програми Console, а потім почали змінювати властивості, а не правильно. Якщо ви насправді використовували шаблон "Бібліотека класів", то інсталяція не пройшла добре.
Ганс Пасант,

Я насправді вибрав бібліотеку класів (.NET Core).
Gigi

2
Правильно, так що це неправильний варіант, якщо ви хочете багатоцільовий. Вам потрібно вибрати .NETStandard, щоб зробити бібліотеку придатною для використання на декількох платформах.
Ганс Пасант,

Це очищає. Ви можете написати відповідь із своїх коментарів, якщо хочете.
Gigi

Відповіді:


119

Вам потрібно вручну відредагувати файл проекту та додати s до TargetFramework за замовчуванням і в основному змінити його на TargetFrameworks . Потім ви згадуєте Монікер з символом ; сепаратор.

Також ви можете помістити посилання на пакети 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 і формую project.json, використовуючи наявну документацію та intellisense, потім відкриваю рішення у VS2017 та використовую вбудоване оновлення. Потім я розгляну файл csproj, щоб з’ясувати, як зробити цю конфігурацію.

Багатоцільове націлювання на більш езотеричні цілі без прізвиська :

Microsoft:

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 показує вам сповіщення, а не 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
Дякую! Це вбиває мене. У "Елементах стилю програмування" Брайана Кернігана, написаному чотири десятиліття тому, він говорить про помилки використання змінних, які відрізняються однією буквою в кінці. Було б набагато зрозуміліше, якби ім’я було "TargetFrameworkList".
howardlo

Приклад, на який ви вказуєте, не включає властивість <TargetFrameworks>.
RenniePet

@RenniePet, дякую! Файл проекту змінився в часі. Я змінив посилання на конкретний коміт, де є <TargetFrameworks>.
Нічний ходок

12

Я насправді вибрав бібліотеку класів (.NET Core).

Це не той шаблон проекту, який вам потрібен, якщо вашій бібліотеці потрібно працювати над кількома цілями платформи. За допомогою цього шаблону проекту ваша бібліотека може бути використана лише в проекті, націленому на .NETCore. Підхід до бібліотеки PCL скасовано, тепер потрібно вибрати .NETStandard.

Ви робите це, починаючи проект із шаблону проекту "Бібліотека класів (.NET Standard)". Тепер у вас є можливість вибрати .NETStandard версію. Поточна сітка сумісності тут .

Сподіваємось, вони постійно оновлюватимуть цю пов’язану статтю. Це все змінюється, .NETStandard 2.0 прибито, але поки що не поставляється. Орієнтована на 2 квартал 2017 року, можливо, на кінець весни, наразі вона показує, що виконано на 97%. Я підслухав, як дизайнери кажуть, що використовувати 1.5 або 1.6 не рекомендується, недостатньо сумісний з 2.0


Як це працює, якщо у вас різні залежності для різних цільових систем? Я маю на увазі, що project.jsonви можете вказати конкретні залежності для цільової структури.
Gigi

1
Я впевнений на 90%, що вам потрібно забути, що це колись існувало. Це був заплутаний безлад, який був лише запобіжним зазором для завантаження .NETCore. Використовуйте сітку сумісності, до якої я прив’язав.
Ганс Пасант,

Я підозрював стільки ж. Велике спасибі за роз'яснення!
Gigi

4
Багатоцільовий @HansPassant все ще є найкращим варіантом, якщо у вас є застарілий код, і в той же час ваша розробка на грінфілді може бути виконана в одному з останніх повнофункціональних варіантів або dotnetcore.
Стефано Рік'ярді,

1
Навіть greenfield ще не обов'язково підходить для .NET Core. Я використовую Azure Function Apps, але їхня версія .NET Core підтримує лише пару активаторів. (Мені потрібні тригери Service Bus, тому я застряг у .NET Framework, і дуже велика бібліотека бізнес-функціональних можливостей може стати багатоцільовою.) Платформа Microsoft зараз заплутана халепа. Це сучасний еквівалент пекла DLL.
McGuireV10

5

Я зробив посібник для початківців з багатоцільового мережевого фреймворку та netcore, який починається з простого виправлення в 1 рядок, а потім проводить вас через кожне з ускладнень.

Найпростіший підхід полягає в тому, щоб спочатку досягти цілі netcore або netstandard. Потім відредагуйте файл csproj і пройдіть ці кроки для інших цілей.

  1. Дізнайтеся про умовні розділи у вашому файлі csproj, щоб ви могли оголосити різні залежності для кожної цілі. Створіть умовні розділи для кожної цілі.
  2. Додайте <Reference />sдля System. * Dll для будь-яких цілей мережі, просто прочитавши те, що повідомлення про помилки збірки відсутні.
  3. Розгляньте залежності NuGet <PackageReference />sу випадках, коли вони не однакові для кожної цілі. Найпростіший фокус - тимчасово повернутися до одиночного націлювання, щоб графічний інтерфейс правильно обробляв посилання на Nuget.
  4. Виконайте справу з кодом, який не компілюється для всіх цілей, вивчаючи творчі різноманітні прийоми, обхідні шляхи та економію часу.
  5. Знайте, коли зменшити свої втрати, коли вартість додавання більшої кількості цілей занадто висока.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.