Come si esegue il multi-target di una libreria di classi .NET Core con csproj?


94

Quando .NET Core utilizzava ancora il project.jsonformato, era possibile creare una libreria di classi destinata a più framework (ad esempio net451, netcoreapp1.0).

Ora che il formato ufficiale del progetto csprojutilizza MSBuild, come si specificano più framework di destinazione? Sto cercando di cercare questo dalle impostazioni di progetto in VS2017, ma sono in grado di indirizzare un solo quadro dei quadri .NET core (non ha nemmeno elencare le altre versioni di .NET framework completo che io non ho installato) :

inserisci qui la descrizione dell'immagine


Questo non è come dovrebbe apparire, dovresti ottenere le scelte .NETStandard 1.x elencate nel menu a discesa. Non è molto chiaro come sia successo, assicurati di scegliere il modello di progetto giusto per iniziare. Dovrebbe essere "Class Library (.NET Standard)". Sembra che tu abbia scelto il modello di app console e quindi abbia iniziato a modificare le proprietà, non nel modo corretto. Se in effetti hai utilizzato il modello della libreria di classi, l'installazione non è andata bene.
Hans Passant

In realtà ho selezionato Class Library (.NET Core).
Gigi

2
Giusto, quindi è quello sbagliato se vuoi multi-target. Devi scegliere un .NETStandard per rendere la libreria utilizzabile su più di una piattaforma.
Hans Passant

Questo lo cancella. Puoi scrivere una risposta dai tuoi commenti, se lo desideri.
Gigi

Risposte:


119

È necessario modificare manualmente il file di progetto e aggiungere i messaggi di posta elettronica al TargetFramework predefinito e sostanzialmente cambiarlo in TargetFrameworks . Poi menzioni il Moniker con un ; separatore.

Inoltre è possibile inserire manualmente i riferimenti al pacchetto Nuget in un ItemGroup condizionale o utilizzando VS Nuget Package Manager.

Ecco come dovrebbe apparire il tuo .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>

Un'altra soluzione alternativa che faccio in questi giorni a causa della documentazione mancante è che creo un progetto in VS2015 e creo project.json utilizzando la documentazione disponibile e intellisense, quindi apro la soluzione in VS2017 e uso l'aggiornamento integrato. Esaminerò quindi il file csproj per capire come realizzare tale configurazione.

Multi-targeting bersagli più esoterici senza un Moniker :

Microsoft:

I PCL non sono consigliati +

Sebbene i PCL siano supportati, gli autori dei pacchetti dovrebbero invece supportare netstandard. .NET Platform Standard è un'evoluzione dei PCL e rappresenta la portabilità binaria tra piattaforme utilizzando un unico moniker che non è legato a uno statico come i moniker portable-a + b + c.

Se si desidera raggiungere un profilo portatile che non dispone di un predefinito moniker così Profili portatili anche non può dedurre TargetFrameworkIdentifier, TargetFrameworkVersione TargetFrameworkProfile. Inoltre, una costante del compilatore non viene definita automaticamente. Infine devi aggiungere tutti i riferimenti agli assembly, nessuno viene fornito per impostazione predefinita.

L'esempio di seguito è tratto da un progetto che utilizzava la dynamicparola chiave, quindi necessitava inoltre Microsoft.CSharpdell'assembly, quindi è possibile vedere come fa riferimento a destinazioni diverse.

<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
Devi farlo modificando manualmente il csproj o può essere fatto tramite VS?
Gigi

1
Il multi targeting di @Gigi deve essere eseguito manualmente. I pacchetti Nuget possono essere eseguiti tramite VS2017 o manualmente.
Aboo

2
Ho riscontrato lo stesso problema e tutto ha funzionato correttamente dopo aver aggiunto la s a <TargetFramework>. Vorrei davvero che queste cose fossero documentate meglio.
Negorath

2
@AsadSaeeduddin è probabile che Resharper ti mostri gli scarabocchi e non Visual Studio. $ (TargetFramework) viene utilizzato solo per rendere un ItemGroup disponibile per un particolare framework / Moniker.
Aboo

2
@ORMapper se il pacchetto NuGet è costruito correttamente, dovrebbe accadere automaticamente durante l'importazione. Significa che se NuGetPackageA supporta già più framework, non è necessario inserirlo in un gruppo di elementi condizionato. Ora, se è necessario fare riferimento a PackageA per .net framework e PackageB per .net core, è necessario inserirlo nel gruppo di elementi condizionati. Non ci sono opzioni nell'interfaccia a partire da oggi (ottobre 2017).
Aboo

24

È possibile modificare manualmente il .csprojfile per questo e impostare la proprietà TargetFrameworks(non TargetFramework).

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

Ad esempio, vedere EFCore.csproj: https://github.com/aspnet/EntityFrameworkCore/blob/951e4826a38ad5499b9b3ec6645e47c825fa842a/src/EFCore/EFCore.csproj


9
Grazie! Mi uccide. In "The Elements of Programming Style" di Brian Kernigan, scritto quattro decenni fa, parla degli errori nell'usare variabili che differiscono di una singola lettera alla fine. Sarebbe stato molto più chiaro se il nome fosse "TargetFrameworkList".
howardlo

L'esempio a cui si punta non include una proprietà <TargetFrameworks>.
RenniePet

@RenniePet, grazie! Il file di progetto è cambiato nel tempo. Ho cambiato il collegamento a un commit concreto, dove c'è <TargetFrameworks>.
Camminatore notturno il

12

In realtà ho selezionato Class Library (.NET Core).

Questo non è il modello di progetto che desideri se la tua libreria deve funzionare su più target di piattaforma. Con questo modello di progetto, la tua libreria può essere utilizzata solo in un progetto destinato a .NETCore. L'approccio alla libreria PCL è stato ritirato, ora devi scegliere un .NETStandard.

A tale scopo, avviare il progetto con il modello di progetto "Libreria di classi (.NET Standard)". Ora hai la possibilità di scegliere la versione .NETStandard. L'attuale griglia di compatibilità è qui .

Si spera che manterranno aggiornato l'articolo collegato. Questo è in evoluzione, .NETStandard 2.0 è stato inchiodato ma non è ancora disponibile. Mirato per il secondo trimestre del 2017, probabilmente alla fine della primavera, attualmente risulta essere completato al 97%. Ho sentito i progettisti dire che l'uso di 1.5 o 1.6 non è raccomandato, non abbastanza compatibile con 2.0


Come funziona se si hanno dipendenze diverse per framework di destinazione diversi? Voglio dire che project.jsonpuoi specificare dipendenze specifiche per un framework di destinazione.
Gigi

1
Sono sicuro al 90% che devi dimenticare che questo è mai esistito. Era un pasticcio confuso che era solo una misura tampone per il bootstrap di .NETCore. Usa la griglia di compatibilità a cui mi sono collegato.
Hans Passant

Lo sospettavo. Grazie mille per aver chiarito!
Gigi

4
@HansPassant multi-target è ancora l'opzione migliore se si dispone di codice legacy e allo stesso tempo lo sviluppo greenfield può essere eseguito in una delle recenti versioni full framework o dotnetcore.
Stefano Ricciardi

1
Nemmeno greenfield è ancora necessariamente compatibile con .NET Core. Sto usando le app per le funzioni di Azure ma la loro versione .NET Core supporta solo un paio di trigger. (Ho bisogno di trigger del bus di servizio, quindi sono bloccato con .NET Framework e una libreria di funzionalità aziendali molto grande potrebbe finire come multi-target.) La piattaforma di Microsoft è un pasticcio aggrovigliato in questo momento. È l'equivalente moderno di DLL Hell.
McGuireV10

5

Ho fatto una guida per principianti al net framework multi-targeting e al netcore che inizia con la semplice correzione di una riga e poi ti guida attraverso ciascuna delle complicazioni.

L'approccio più semplice è far funzionare prima un target netcore o netstandard. Quindi modificare il file csproj e seguire questi passaggi per gli altri target.

  1. Informazioni sulle sezioni condizionali nel file csproj, in modo da poter dichiarare dipendenze diverse per ogni destinazione. Crea sezioni condizionali per ogni destinazione.
  2. Aggiungi <Reference />sper System. * Dll per qualsiasi target netframework semplicemente leggendo ciò che i messaggi di errore di build dicono che manca.
  3. Gestire le dipendenze NuGet <PackageReference />snei casi in cui non sono le stesse per ogni destinazione. Il trucco più semplice è ripristinare temporaneamente il targeting singolo in modo che la GUI gestisca correttamente i riferimenti Nuget per te.
  4. Gestisci il codice che non si compila su tutti gli obiettivi, apprendendo una varietà creativa di tecniche, soluzioni alternative e risparmio di tempo.
  5. Sapere quando tagliare le perdite quando il costo per aggiungere più obiettivi è troppo alto.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.