Wie können Sie eine .NET Core-Klassenbibliothek mit csproj auf mehrere Ziele ausrichten?

91

Wenn .NET Core das project.jsonFormat noch verwendete , konnten Sie eine Klassenbibliothek erstellen erstellen, die auf mehrere Frameworks abzielt (z. B. net451, netcoreapp1.0).

csprojWie können Sie nun, da das offizielle Projektformat MSBuild verwendet, mehrere Frameworks für das Targeting angeben? Ich versuche , dies aus den Projekteinstellungen in VS2017 zu suchen, aber ich bin in der Lage, nur einen einzigen Rahmen von der .NET - Frameworks Core - Ziel (es nicht einmal die andere voll .NET Framework - Versionen auflistet , die ich tue installiert haben) ::

Geben Sie hier die Bildbeschreibung ein

Gigi
quelle
So soll es nicht aussehen, Sie sollten die in der Dropdown-Liste aufgeführten .NETStandard 1.x-Optionen erhalten. Es ist nicht ganz klar, wie dies passiert ist. Wählen Sie unbedingt die richtige Projektvorlage aus, um loszulegen. Sollte "Klassenbibliothek (.NET Standard)" sein. Sieht so aus, als hätten Sie die Console App-Vorlage ausgewählt und dann damit begonnen, die Eigenschaften nicht richtig zu ändern. Wenn Sie tatsächlich die Klassenbibliotheksvorlage verwendet haben, verlief die Installation nicht gut.
Hans Passant
Ich habe tatsächlich Class Library (.NET Core) ausgewählt.
Gigi
2
Richtig, das ist also falsch, wenn Sie mehrere Ziele verfolgen möchten. Sie müssen einen .NETStandard auswählen, damit die Bibliothek auf mehr als einer Plattform verwendet werden kann.
Hans Passant
Das macht es klar. Sie können eine Antwort aus Ihren Kommentaren schreiben, wenn Sie möchten.
Gigi

Antworten:

118

Sie müssen die Projektdatei manuell bearbeiten und s zum Standard- TargetFramework hinzufügen und es grundsätzlich in TargetFrameworks ändern . Dann erwähnen Sie den Moniker mit einem ;Separator.

Sie können die Nuget-Paketreferenzen auch manuell oder mithilfe von VS Nuget Package Manager in eine bedingte ItemGroup einfügen.

So sollte Ihre .csproj aussehen:

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

Eine andere Problemumgehung, die ich heutzutage aufgrund fehlender Dokumentation mache, besteht darin, dass ich ein Projekt in VS2015 erstelle und die Datei project.json mit der verfügbaren Dokumentation und Intellisense erstelle. Öffnen Sie dann die Lösung in VS2017 und verwenden Sie das integrierte Upgrade. Ich werde mir dann die csproj-Datei ansehen, um herauszufinden, wie diese Konfiguration durchgeführt werden kann.

Multi-Targeting von esoterischeren Zielen ohne Moniker :

Microsoft:

PCLs werden nicht empfohlen +

Obwohl PCLs unterstützt werden, sollten Paketautoren stattdessen netstandard unterstützen. Der .NET Platform Standard ist eine Weiterentwicklung von PCLs und stellt die binäre Portabilität über Plattformen hinweg dar, indem ein einzelner Moniker verwendet wird, der nicht an einen statischen wie tragbare a + b + c-Moniker gebunden ist.

Wenn Sie auf ein tragbares Profil abzielen möchten, hat es keinen vordefinierten Spitznamen, sodass auch tragbare Profile nicht auf , und schließen TargetFrameworkIdentifierkönnenTargetFrameworkVersionTargetFrameworkProfile . Auch eine Compilerkonstante wird nicht automatisch definiert. Schließlich müssen Sie alle Assemblyreferenzen hinzufügen, die standardmäßig nicht bereitgestellt werden.

Das folgende Beispiel stammt aus einem Projekt, das das dynamicSchlüsselwort verwendet hat, sodass zusätzlich die Microsoft.CSharpAssembly benötigt wurde. Sie können also sehen, wie die Referenzen für verschiedene Ziele sind.

<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>
Aboo
quelle
1
Müssen Sie dies tun, indem Sie das csproj manuell bearbeiten, oder kann es über VS erfolgen?
Gigi
1
@ Gigi Multi Targeting muss manuell erfolgen. Nuget-Pakete können über VS2017 oder manuell erstellt werden.
Aboo
2
Ich hatte das gleiche Problem und alles hat gut funktioniert, nachdem ich das s zu <TargetFramework> hinzugefügt habe. Ich wünschte wirklich, diese Dinge wären besser dokumentiert.
Negorath
2
@AsadSaeeduddin Es besteht die Möglichkeit, dass Resharper Ihnen die Schnörkel zeigt und nicht Visual Studio. Das $ (TargetFramework) wird nur verwendet, um eine ItemGroup für ein bestimmtes Framework / Moniker verfügbar zu machen.
Aboo
2
@ORMapper Wenn das NuGet-Paket korrekt erstellt wurde, sollte dies beim Import automatisch geschehen. Das heißt, wenn NuGetPackageA bereits mehrere Frameworks unterstützt, müssen Sie es nicht in eine konditionierte Elementgruppe einfügen. Wenn Sie nun auf PackageA für .net Framework und PackageB für .net Core verweisen müssen, muss dies in eine konditionierte Elementgruppe eingefügt werden. Ab heute (Oktober 2017) gibt es keine Option in der Benutzeroberfläche.
Aboo
24

Sie können die .csprojDatei hierfür manuell bearbeiten und die Eigenschaft TargetFrameworks(nicht TargetFramework) festlegen .

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

Beispiel EFCore.csproj: https://github.com/aspnet/EntityFrameworkCore/blob/951e4826a38ad5499b9b3ec6645e47c825fa842a/src/EFCore/EFCore.csproj

Nachtwanderer
quelle
9
Vielen Dank! Es bringt mich um. In Brian Kernigans "Die Elemente des Programmierstils", der vor vier Jahrzehnten geschrieben wurde, spricht er über die Fehler bei der Verwendung von Variablen, die sich am Ende durch einen einzelnen Buchstaben unterscheiden. Es wäre viel klarer gewesen, wenn der Name "TargetFrameworkList" gewesen wäre.
Howardlo
Das Beispiel, auf das Sie zeigen, enthält keine <TargetFrameworks> -Eigenschaft.
RenniePet
@ RenniePet, danke! Die Projektdatei hat sich zeitlich geändert. Ich habe den Link zu einem konkreten Commit geändert, in dem sich <TargetFrameworks> befindet.
Nachtwanderer
12

Ich habe tatsächlich Class Library (.NET Core) ausgewählt.

Dies ist nicht die gewünschte Projektvorlage, wenn Ihre Bibliothek auf mehreren Plattformzielen arbeiten muss. Mit dieser Projektvorlage kann Ihre Bibliothek immer nur in einem Projekt verwendet werden, das auf .NETCore abzielt. Der PCL-Bibliotheksansatz wurde eingestellt. Sie müssen jetzt einen .NETStandard auswählen.

Sie starten dazu das Projekt mit der Projektvorlage "Klassenbibliothek (.NET Standard)". Sie haben jetzt die Möglichkeit, die .NETStandard-Version auszuwählen. Das aktuelle Kompatibilitätsraster finden Sie hier .

Hoffentlich halten sie diesen verlinkten Artikel auf dem neuesten Stand. Dies ist im Fluss, .NETStandard 2.0 wurde festgenagelt, wird aber noch nicht ausgeliefert. Geplant für das zweite Quartal 2017, voraussichtlich Ende des Frühlings, werden derzeit 97% erreicht. Ich habe gehört, wie die Designer sagten, dass die Verwendung von 1.5 oder 1.6 nicht empfohlen wird, nicht kompatibel genug mit 2.0

Hans Passant
quelle
Wie funktioniert es, wenn Sie unterschiedliche Abhängigkeiten für unterschiedliche Ziel-Frameworks haben? Ich meine, project.jsonSie könnten bestimmte Abhängigkeiten für ein Zielframework angeben.
Gigi
1
Ich bin zu 90% sicher, dass Sie vergessen müssen, dass dies jemals existiert hat. Es war ein verwirrendes Durcheinander, das nur eine Lücke war, um .NETCore zu booten. Verwenden Sie das Kompatibilitätsraster, mit dem ich verknüpft bin.
Hans Passant
Das habe ich auch vermutet. Vielen Dank für die Klarstellung!
Gigi
4
@HansPassant Multi-Target ist immer noch die beste Option, wenn Sie über Legacy-Code verfügen und gleichzeitig Ihre Greenfield-Entwicklung in einem der neuesten Full-Framework-Varianten oder Dotnetcore durchgeführt werden kann.
Stefano Ricciardi
1
Noch nicht einmal Greenfield ist unbedingt .NET Core-freundlich. Ich verwende Azure Function Apps, aber die .NET Core-Version unterstützt nur einige Trigger. (Ich benötige Service Bus-Trigger, daher bleibe ich bei .NET Framework, und eine sehr große Bibliothek mit Geschäftsfunktionen kann sich als Multi-Target-Lösung herausstellen.) Die Microsoft-Plattform ist derzeit ein Wirrwarr. Es ist das moderne Äquivalent zu DLL Hell.
McGuireV10
5

Ich habe einen Anfängerleitfaden für Multi-Targeting-Net-Framework und Netcore erstellt, der mit dem einfachen 1-Zeilen-Fix beginnt und Sie dann durch die einzelnen Komplikationen führt.

Der einfachste Ansatz besteht darin, zuerst ein Netcore- oder Netstandard-Ziel zum Laufen zu bringen. Bearbeiten Sie dann die csproj-Datei und führen Sie diese Schritte für die anderen Ziele aus.

  1. Erfahren Sie mehr über bedingte Abschnitte in Ihrer csproj-Datei, damit Sie für jedes Ziel unterschiedliche Abhängigkeiten deklarieren können. Erstellen Sie bedingte Abschnitte für jedes Ziel.
  2. Add <Reference />sfor System. * DLLs für alle Netframework-Ziele, indem Sie einfach lesen, was in den Build-Fehlermeldungen fehlt.
  3. Umgang mit NuGet-Abhängigkeiten <PackageReference />s in Fällen, in denen sie nicht für jedes Ziel gleich sind. Der einfachste Trick besteht darin, vorübergehend auf einzelne Ziele zurückzugreifen, damit die GUI die Nuget-Referenzen für Sie korrekt verarbeitet.
  4. Behandeln Sie Code, der nicht für alle Ziele kompiliert werden kann, indem Sie eine kreative Vielfalt an Techniken, Problemumgehungen und Zeitersparnissen erlernen.
  5. Wissen Sie, wann Sie Ihre Verluste reduzieren müssen, wenn die Kosten für das Hinzufügen weiterer Ziele zu hoch sind.
Chris F. Carroll
quelle