¿Cómo se realiza una selección múltiple de una biblioteca de clases de .NET Core con csproj?

94

Cuando .NET Core todavía usaba el project.jsonformato, podía crear una biblioteca de clases dirigida a varios marcos (por ejemplo, net451, netcoreapp1.0).

Ahora que el formato del proyecto oficial está csprojusando MSBuild, ¿cómo se especifican varios marcos para apuntar? Estoy tratando de buscar estas cosas en la configuración del proyecto en VS2017, pero yo soy capaz sólo de apuntar a un único marco de los marcos .NET Core (que ni siquiera tiene una lista de las otras versiones completas de .NET Framework, que yo no he instalado) :

ingrese la descripción de la imagen aquí

Gigi
fuente
No es así como se supone que debe verse, debería obtener las opciones .NETStandard 1.x que se enumeran en el menú desplegable. No está muy claro cómo sucedió esto, asegúrese de elegir la plantilla de proyecto correcta para comenzar. Debe ser "Biblioteca de clases (.NET Standard)". Parece que eligió la plantilla de la aplicación de consola y luego comenzó a cambiar las propiedades, no de la manera correcta. Si de hecho usó la plantilla de Biblioteca de clases, la instalación no fue bien.
Hans Passant
De hecho, seleccioné Class Library (.NET Core).
Gigi
2
Correcto, entonces ese es el incorrecto si quieres tener un objetivo múltiple. Debe elegir un .NETStandard para que la biblioteca se pueda utilizar en más de una plataforma.
Hans Passant
Eso lo aclara. Puede escribir una respuesta a partir de sus comentarios si lo desea.
Gigi

Respuestas:

119

Necesita editar manualmente el archivo del proyecto y agregar s al TargetFramework predeterminado y básicamente cambiarlo a TargetFrameworks . Luego mencionas el apodo con un ;separador.

También puede poner las referencias del paquete Nuget en un ItemGroup condicional manualmente o usando VS Nuget Package Manager.

Así es como debería verse su .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>

Otra solución alternativa que hago en estos días debido a la falta de documentación es que creo un proyecto en VS2015 y formo el project.json usando la documentación disponible e intellisense, luego abro la solución en VS2017 y uso la actualización incorporada. Luego miraré el archivo csproj para averiguar cómo hacer que suceda esa configuración.

Orientación múltiple a objetivos más esotéricos sin un Moniker :

Microsoft:

No se recomiendan los PCL +

Aunque se admiten PCL, los autores de paquetes deberían admitir netstandard en su lugar. El .NET Platform Standard es una evolución de las PCL y representa la portabilidad binaria entre plataformas utilizando un único apodo que no está vinculado a un estático como los apodos portable-a + b + c.

Si desea dirigirse a un perfil portátil que no tiene predefinido apodo de manera Perfiles portátiles también no puede inferir TargetFrameworkIdentifier, TargetFrameworkVersiony TargetFrameworkProfile. Además, una constante del compilador no se define automáticamente. Finalmente, debe agregar todas las referencias de ensamblaje, ninguna se proporciona por defecto.

Este ejemplo a continuación se tomó de un proyecto que usó la dynamicpalabra clave, por lo que también necesitaba el Microsoft.CSharpensamblaje, por lo que puede ver cómo son las referencias para diferentes objetivos.

<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
fuente
1
¿Tiene que hacer esto editando el csproj manualmente, o se puede hacer a través de VS?
Gigi
1
La orientación múltiple de @Gigi debe realizarse manualmente. Los paquetes Nuget se pueden hacer a través de VS2017 o manualmente.
Aboo
2
Estaba teniendo el mismo problema y todo funcionó bien después de agregar los s a <TargetFramework>. Realmente desearía que estas cosas estuvieran mejor documentadas.
Negorath
2
@AsadSaeeduddin es probable que Resharper le muestre los garabatos y no Visual Studio. El $ (TargetFramework) solo se usa para hacer que un ItemGroup esté disponible para un marco / Moniker en particular.
Aboo
2
@ORMapper si el paquete NuGet está construido correctamente, esto debería suceder automáticamente al importar. Lo que significa que si NuGetPackageA ya admite varios marcos, no es necesario que lo coloque en un grupo de elementos condicionado. Ahora, si necesita hacer referencia a PackageA para .net framework y PackageB para .net core, entonces debe colocarse en el grupo de elementos condicionados. No hay ninguna opción en la interfaz a partir de hoy (octubre de 2017).
Aboo
24

Puede editar manualmente el .csprojarchivo para esto y establecer TargetFrameworks(no TargetFramework) la propiedad.

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

Por ejemplo, consulte EFCore.csproj: https://github.com/aspnet/EntityFrameworkCore/blob/951e4826a38ad5499b9b3ec6645e47c825fa842a/src/EFCore/EFCore.csproj

Caminante nocturno
fuente
9
¡Gracias! Eso me mata. En "Los elementos del estilo de programación" de Brian Kernigan, escrito hace cuatro décadas, habla de los errores de usar variables que se diferencian por una sola letra al final. Habría sido mucho más claro si el nombre fuera "TargetFrameworkList".
howardlo
El ejemplo que señala no incluye una propiedad <TargetFrameworks>.
RenniePet
@RenniePet, ¡gracias! El archivo del proyecto ha cambiado con el tiempo. Cambié el enlace a una confirmación concreta, donde está <TargetFrameworks>.
Night walker
12

De hecho, seleccioné Class Library (.NET Core).

Esa no es la plantilla de proyecto que desea si su biblioteca necesita trabajar en múltiples plataformas. Con esta plantilla de proyecto, su biblioteca solo se puede usar en un proyecto que tenga como objetivo .NETCore. El enfoque de la biblioteca PCL se retiró, ahora debe elegir un .NETStandard.

Para ello, inicie el proyecto con la plantilla de proyecto "Biblioteca de clases (.NET Standard)". Ahora tiene la opción de elegir la versión .NETStandard. La cuadrícula de compatibilidad actual está aquí .

Con suerte, mantendrán actualizado ese artículo vinculado. Esto está en proceso de cambio, .NETStandard 2.0 se definió pero aún no se envía. Apuntado para el segundo trimestre de 2017, probablemente a finales de la primavera, actualmente muestra un 97% hecho. Escuché a los diseñadores decir que no se recomienda usar 1.5 o 1.6, no es lo suficientemente compatible con 2.0

Hans Passant
fuente
¿Cómo funciona si tiene diferentes dependencias para diferentes marcos de destino? Quiero decir project.jsonque podría especificar dependencias específicas para un marco de destino.
Gigi
1
Estoy 90% seguro de que debes olvidar que esto alguna vez existió. Fue un lío confuso que fue solo una medida provisional para arrancar .NETCore. Use la cuadrícula de compatibilidad a la que me vinculé.
Hans Passant
Lo sospechaba mucho. ¡Muchas gracias por aclarar!
Gigi
4
@HansPassant multi-target sigue siendo la mejor opción si tiene un código heredado y, al mismo tiempo, su desarrollo totalmente nuevo se puede realizar en una de las versiones recientes de framework completo o dotnetcore.
Stefano Ricciardi
1
Ni siquiera greenfield es necesariamente compatible con .NET Core todavía. Estoy usando Azure Function Apps, pero su versión de .NET Core solo admite un par de activadores. (Necesito activadores de Service Bus, así que estoy atascado con .NET Framework, y una biblioteca de funcionalidad empresarial muy grande puede terminar como multi-objetivo). La plataforma de Microsoft es un enredo en este momento. Es el equivalente moderno de DLL Hell.
McGuireV10
5

Hice una guía para principiantes sobre el marco de red de orientación múltiple y netcore que comienza con la solución simple de 1 línea y luego lo guía a través de cada una de las complicaciones.

El enfoque más simple es hacer que un objetivo netcore o netstandard funcione primero. Luego edite el archivo csproj y siga estos pasos para los otros destinos.

  1. Obtenga información sobre las secciones condicionales en su archivo csproj, de modo que pueda declarar diferentes dependencias para cada objetivo. Crea secciones condicionales para cada objetivo.
  2. Agregue <Reference />spara System. * Dlls para cualquier objetivo de netframework simplemente leyendo lo que dicen que falta en los mensajes de error de compilación.
  3. Tratar las dependencias de NuGet <PackageReference />s en los casos en que no sean las mismas para cada destino. El truco más fácil es volver temporalmente a la orientación única para que la GUI maneje las referencias de Nuget correctamente por usted.
  4. Trate con el código que no se compila en todos los objetivos, aprendiendo una variedad creativa de técnicas, soluciones y ahorradores de tiempo.
  5. Sepa cuándo reducir sus pérdidas cuando el costo de agregar más objetivos es demasiado alto.
Chris F Carroll
fuente