Как с помощью csproj выполнить несколько задач для библиотеки классов .NET Core?


96

Когда .NET Core все еще использовал этот project.jsonформат, вы могли создать библиотеку классов, ориентированную на несколько платформ (например, net451, netcoreapp1.0).

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

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


Это не то, как это должно выглядеть, вы должны получить варианты .NETStandard 1.x, перечисленные в раскрывающемся списке. Не очень понятно, как это произошло, для начала обязательно выберите правильный шаблон проекта. Должен быть «Библиотека классов (стандарт .NET)». Похоже, вы выбрали шаблон консольного приложения, а затем начали изменять свойства, а не правильно. Если вы действительно использовали шаблон библиотеки классов, то установка прошла не очень хорошо.
Ханс

Я выбрал библиотеку классов (.NET Core).
Gigi

2
Верно, так что это неправильный вариант, если вы хотите использовать несколько целей. Вы должны выбрать .NETStandard, чтобы библиотеку можно было использовать более чем на одной платформе.
Hans Passant

Это все проясняет. Вы можете написать ответ из своих комментариев, если хотите.
Gigi

Ответы:


122

Вам нужно вручную отредактировать файл проекта и добавить 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 и представляет двоичную переносимость между платформами с использованием единственного прозвища, которое не привязано к статическим именам, таким как Portable-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, тогда это нужно поместить в условную группу элементов. На сегодняшний день (октябрь 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 05

@RenniePet, спасибо! Файл проекта со временем изменился. Я изменил ссылку на конкретный коммит, где есть <TargetFrameworks>.
Night Walker

12

Я выбрал библиотеку классов (.NET Core).

Это не тот шаблон проекта, который вам нужен, если ваша библиотека должна работать на нескольких целевых платформах. С этим шаблоном проекта ваша библиотека может быть использована только в проекте, ориентированном на .NETCore. Подход с использованием библиотеки PCL был исключен, теперь вам нужно выбрать .NETStandard.

Это можно сделать, запустив проект с помощью шаблона проекта «Библиотека классов (.NET Standard)». Теперь у вас есть возможность выбрать версию .NETStandard. Текущая таблица совместимости находится здесь .

Надеюсь, они обновят эту связанную статью. Это постоянно меняется, .NETStandard 2.0 был прибит, но еще не выпущен. Ориентировано на второй квартал 2017 года, вероятно, на конец весны, в настоящее время выполнено 97%. Я слышал, как дизайнеры говорили, что использование 1.5 или 1.6 не рекомендуется, недостаточно совместимо с 2.0.


Как это работает, если у вас разные зависимости для разных целевых фреймворков? Я имею в виду, что project.jsonвы можете указать конкретные зависимости для целевой платформы.
Gigi

1
Я на 90% уверен, что вам нужно забыть, что это когда-либо существовало. Это был запутанный беспорядок, который был лишь временной мерой для начальной загрузки .NETCore. Используйте таблицу совместимости, к которой я привязан.
Hans Passant

Я так и подозревал. Большое спасибо за разъяснения!
Gigi

4
@HansPassant multi-target по-прежнему является лучшим вариантом, если у вас есть унаследованный код, и в то же время ваша разработка с нуля может быть выполнена в одном из последних вариантов полной инфраструктуры или dotnetcore.
Стефано

1
Даже greenfield еще не обязательно совместим с .NET Core. Я использую приложения-функции Azure, но их версия .NET Core поддерживает только несколько триггеров. (Мне нужны триггеры служебной шины, поэтому я застрял на .NET Framework, и очень большая библиотека бизнес-функций может оказаться многоцелевой.) Платформа Microsoft сейчас запутана. Это современный эквивалент DLL Hell.
McGuireV10

5

Я сделал руководство для новичков по сетевой структуре и сетевому ядру с множественным таргетингом, которое начинается с простого исправления в одну строку, а затем проводит вас через каждую из сложностей.

Самый простой подход - сначала заставить работать цель netcore или netstandard. Затем отредактируйте файл csproj и выполните эти шаги для других целей.

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