¿Cómo consigo que los proyectos de .NET Core copien las referencias de NuGet al resultado de la compilación?

111

Estoy tratando de escribir un sistema de complementos con .NET Core, y uno de mis requisitos es poder distribuir la DLL del complemento junto con sus dependencias al usuario para su instalación.

Sin embargo, no puedo averiguar cómo incluir mis dependencias de NuGet como un artefacto de compilación y hacer que se envíen a la carpeta de compilación, sin tener que usarlas dotnet publishcomo un truco. ¿Hay alguna forma de que pueda especificar esto en el archivo .csproj (archivo de proyecto)?

chyyran
fuente
2
¿Por qué usarlo dotnet publishsería un truco? Incluya el comando en su archivo csproj como un script de compilación posterior.
Austin Drenski
3
dotnet publisharroja todo el marco en la carpeta de publicación, ya que estoy escribiendo un complemento, la mayoría de los archivos no son necesarios ya que el programa de arranque ya cargaría el marco. Estoy buscando algo similar a cómo funcionan las compilaciones en .NET Framework.
chyyran
¿E incluir <CopyToOutputDirectory>Always</CopyToOutputDirectory>en su csproj en cada una de las DLL que desea mover no funciona? ¿Quizás combinado con un <link>nodo?
Austin Drenski
7
<PackageReference/>no es compatible <CopyToOutputDirectory>.
chyyran
1
Sin embargo, el "marco completo" proviene de NuGet ... y si opta por copiar todos los ensamblados de NuGet en la salida de la compilación, los obtendrá todos ...
Martin Ullrich

Respuestas:

179

Puede agregar esto <PropertyGroup>dentro de su archivo csproj para hacer cumplir la copia de ensamblados NuGet en la salida de la compilación:

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

Sin embargo, tenga en cuenta que bin/Release/netcoreapp*/*se supone que la salida de la compilación ( ) no es portátil y distribuible, la salida de sí lo dotnet publishes. Pero en su caso, copiar los ensamblados en el resultado de la compilación probablemente sea muy útil para realizar pruebas. Pero tenga en cuenta que también puede usar la DependencyContextAPI para resolver las DLL y sus ubicaciones que son parte del gráfico de dependencia de la aplicación en lugar de enumerar un directorio local.

Martin Ullrich
fuente
7
Causa copiar todos los dlls, no solo los dlls de Nuget
Mohammad Dayyan
2
Core 2 También obtengo todas las DLL de Microsoft. No estoy seguro de por qué, pero antes solo obtenía NuGet, pero luego dejó de hacerlo. molesto
Piotr Kula
4
@MartinUllrich ¿Puedes dar más detalles sobre el DependencyContext? ¿Cómo puedo usarlo para encontrar una DLL que no está en el directorio de la aplicación? ¿Dónde está de todos modos?
ygoe
2
no funciona para mí asp.net core no copia System.ValueTuple.dll
Ali Yousefi
1
@AliYousefie system.valuietuple para proyectos de .net framework ya no debería provenir de NuGet en versiones recientes de .net framework y herramientas de compilación
Martin Ullrich
10

Puede utilizar PostBuildEvent para automatizar la implementación del módulo en la compilación.

Para obtener los ensamblados de NuGet en la carpeta de compilación, agregue csproj de su módulo

<PropertyGroup>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>

Defina qué archivos de módulo desea donde use Incluir / Excluir (modifique la ruta según sea necesario)

<ItemGroup>
    <ModuleFiles
      Include="$(TargetDir)*.dll"
      Exclude="$(TargetDir)System*.dll;$(TargetDir)Microsoft*.dll"
      DestinationPath="$(SolutionDir)src\MyProject\Modules\MyModule\%(Filename)%(Extension)">
    </ModuleFiles>
</ItemGroup>

Restablezca su carpeta de compilación a la predeterminada y agregue PostbuildEvent

<Target Name="PublishModule" AfterTargets="PostBuildEvent" Inputs="@(ModuleFiles)" Outputs="@(ModuleFiles->'%(DestinationPath)')">
    <WriteLinesToFile File="$(SolutionDir)src\[YOURAPP]\app_offline.htm" />
    <Copy SourceFiles="@(ModuleFiles)" DestinationFiles="@(ModuleFiles->'%(DestinationPath)')" />
    <Delete Files="$(SolutionDir)src\[YOURAPP]\app_offline.htm" />
</Target>

Incluyo app_offline para reciclar la aplicación si ya se está ejecutando para evitar errores de archivo en uso.

Xeevis
fuente
En mi proyecto, tengo una dependencia en la biblioteca Nuget "Microsoft.Extensions.Logging.Log4Net.AspNetCore", y no es parte de NetCore, por lo que este enfoque no funcionará
sad_robot
4

Añadiendo

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

no funcionó, pero agregando esto al archivo Framework .csproj:

<RestoreProjectStyle>PackageReference</RestoreProjectStyle>

hizo.

Mike Brunner
fuente
Esto funcionó bien para mí cuando hacía referencia a las bibliotecas .net Standard 2.0 desde un proyecto .Net Framework 4.7.2. Nada más lo arregló.
Grungondola
3

"Resolví" (trabajo creado alrededor) esto de una manera más simple.

En la compilación posterior

dotnet publish "$(ProjectFileName)" --no-build -o pub
xcopy "$(ProjectDir)pub\3rdPartyProvider.*.dll" "$(OutDir)"

pub es la carpeta donde desea que se coloquen las cosas publicadas

NOTA: dependiendo de la versión dotnet.exeque utilice, es --no-buildposible que el comando no esté disponible.

Por ejemplo, no disponible en v2.0.3; y disponible en v2.1.402. Sé que VS2017 Update4 tenía v2.0.3. Y Update8 tiene 2.1.x

Actualizar:

La configuración anterior funcionará en el entorno de depuración básico, pero para ponerla en el entorno de producción / servidor de compilación se necesita más. En este ejemplo en particular que tuve que resolver, lo construimos Release|x64y por Release|x86separado. Así que contabilicé ambos. Pero para admitir el dotnet publishcomando de compilación posterior , primero agregué RuntimeIdentifieral archivo del proyecto.

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
  <OutputPath>..\..\lib\</OutputPath>
  <RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
  <OutputPath>..\..\lib\</OutputPath>
  <RuntimeIdentifier>win-x86</RuntimeIdentifier>
</PropertyGroup>

¿Por qué lo necesitaba y por qué puedes escapar sin él? Necesitaba esto porque mi programa de compilación está configurado para interceptar la advertencia MSB3270 y fallar la compilación si aparece. Esta advertencia dice, "oye, algunos archivos de tus dependencias tienen un formato incorrecto". ¿Pero recuerdas el objetivo de este ejercicio? Necesitamos extraer las DLL de dependencia de paquetes. Y en muchos casos no importa si esta advertencia está ahí porque la siguiente compilación posterior no importa. Una vez más, este es mi programa de construcción que se preocupa. Entonces, solo agregué RuntimeIdentifiera 2 configuraciones que uso durante la compilación de producción.

Construcción de publicación completa

if not exist "$(ProjectDir)obj\$(ConfigurationName)" mkdir "$(ProjectDir)obj\$(ConfigurationName)"
xcopy  "$(ProjectDir)obj\$(PlatformName)\$(ConfigurationName)" "$(ProjectDir)obj\$(ConfigurationName)" /E /R /Y

if $(ConfigurationName) == Release (
    dotnet publish "$(ProjectFileName)" --runtime win-$(PlatformName) --no-build -c $(ConfigurationName) -o pub --no-restore --no-dependencies
) else (
    dotnet publish "$(ProjectFileName)" --no-build -c $(ConfigurationName) -o pub --no-restore --no-dependencies
)

xcopy "$(ProjectDir)pub\my3rdPartyCompany.*.dll" "$(OutDir)" /Y /R

Explicación: dotnet publish está buscando obj\Debugo obj\Release. No lo tenemos durante la compilación porque la compilación crea obj\x64\Releaseo obj\x86\Release. Las líneas 1 y 2 mitigan este problema. En la línea 3 le digo dotnet.exeque use una configuración específica y un tiempo de ejecución de destino. De lo contrario, cuando este es el modo de depuración, no me importan las advertencias ni las cosas en tiempo de ejecución. Y en la última línea, simplemente tomo mis dlls y los copio en la carpeta de salida. Trabajo hecho.

TS
fuente
El parámetro "-c Release" es necesario para el comando "dotnet publish" si el proyecto no tiene configuración de depuración (como en mi caso). Así que usé este lote como evento posterior a la compilación: dotnet publish "$(ProjectFileName)" -c Release --no-build -o bin\pub xcopy "$(ProjectDir)pub\PostSharp.dll" "$(OutDir)"
Xtro
0

Junto con la respuesta anterior: tengo esto funcionando muy bien en la línea de comando del evento posterior a la compilación: en Visual Studio. Recorre una selección de archivos DLL (System * .dll y Microsoft .dll) * y luego omite la eliminación de archivos DLL específicos. System.Data.SqlClient.dll y System.Runtime.Loader.dll

for %%f in ($(OutDir)System*.dll $(OutDir)Microsoft*.dll) do if not %%f == $(OutDir)System.Data.SqlClient.dll if not %%f == $(OutDir)System.Runtime.Loader.dll del %%f
lubina
fuente