Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
I'm trying to write a plugin system with .NET Core, and one of my requirements are to be able to distribute the plugin DLL along with its dependencies to the user for install.
However, I can't figure out how to include my NuGet dependencies as a build artifact and have them output to the build folder, without having to use
dotnet publish
as a hack. Is there some way I can specify this in the .csproj file (project file)?
–
–
–
–
You can add this to a
<PropertyGroup>
inside your csproj file to enforce copying NuGet assemblies to the build output:
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
However, note that the build output (bin/Release/netcoreapp*/*
) is not supposed to be portable and distributable, the output of dotnet publish
is. But in your case, copying the assemblies to the build output is probably very useful for testing purposes. But note that you could also use the DependencyContext
api to resolve the DLLs and their locations that are part of the application's dependency graph instead of enumerating a local directory.
–
–
–
You can use PostBuildEvent to automate module deployment on build.
To get NuGet assemblies in build folder add in csproj of your module
<PropertyGroup>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
Define what module files you want where using Include/Exclude (modify path as necessary)
<ItemGroup>
<ModuleFiles
Include="$(TargetDir)*.dll"
Exclude="$(TargetDir)System*.dll;$(TargetDir)Microsoft*.dll"
DestinationPath="$(SolutionDir)src\MyProject\Modules\MyModule\%(Filename)%(Extension)">
</ModuleFiles>
</ItemGroup>
Reset your build folder to default and add 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>
I'm including app_offline to recycle app if it's already running to avoid file in use errors.
–
didn't work, but adding this to the Framework .csproj file:
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
–
–
–
I am using .NET 5 and here is my solution to my similar issue.
Structure:
Project-A (Contained Selenium Nuget References, and selenium code)
Project-B (A unit test project, which calls methods in Project-A)
Issue:
When building the solution, the chromedriver.exe file was appearing in the Project-A bin folder, but would not get copied to the Project-B bin folder, so the unit tests could not execute. An exception was thrown saying chromedriver.exe was not found.
Solution:
Modify the attribute in Project-A for the Selenium ChromeDriver NuGet package reference to only consider 'contentfiles;analyzers' as private assets. The default value for this is 'contentfiles;analyzers;build' when not specified. This now means it is okay to flow the output files of the build to parent referencing projects, but not contentfiles or analyzers, where as 'build' was also previously considered a private asset and would not flow through to parent projects.
Before (in Project-A.csproj):
<ItemGroup>
<PackageReference Include="Selenium.Support" Version="3.141.0" />
<PackageReference Include="Selenium.WebDriver" Version="3.141.0" />
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="87.0.4280.8800" />
</ItemGroup>
After (in Project-A.csproj):
<ItemGroup>
<PackageReference Include="Selenium.Support" Version="3.141.0" />
<PackageReference Include="Selenium.WebDriver" Version="3.141.0" />
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="87.0.4280.8800">
<PrivateAssets>contentfiles;analyzers</PrivateAssets>
</PackageReference>
</ItemGroup>
I found this information in this link:
https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files#controlling-dependency-assets
Hope this helps someone! Good luck.
dotnet publish "$(ProjectFileName)" --no-build -o pub
xcopy "$(ProjectDir)pub\3rdPartyProvider.*.dll" "$(OutDir)"
pub
is the folder where you want your published stuff go for staging
NOTE: depending on what version of dotnet.exe
you use, command --no-build
may not be available.
For example, not available in v2.0.3; and available in v2.1.402. I know that VS2017 Update4 had v2.0.3. And Update8 has 2.1.x
Update:
The setup above will work in the basic debug environment but to put it into build server/production environment more is needed. In this particular example that I had to solve, we build Release|x64
and Release|x86
separately. So I accounted for both. But to support the post build dotnet publish
command, I first added RuntimeIdentifier
to project file.
<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>
Why I needed it and why you can get away without it? I needed this because my build program is set to intercept warning MSB3270, and fail the build if it appears. This warning says, "hey, some files in your dependencies are of wrong format". But do you remember the goal of this exercise? We need to pull package dependency DLLs. And in many cases it doesn't matter if this warning is there because following post build does not care. Again, this is my build program that cares. So, I only added RuntimeIdentifier
to 2 configurations I use during production build.
Full Post build
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
Explanation: dotnet publish is looking for obj\Debug
or obj\Release
. We don't have it during the build because build creates obj\x64\Release
or obj\x86\Release
. Line 1 and 2 mitigate this issue. In line 3 I tell dotnet.exe
to use specific configuration and target runtime. Otherwise, when this is debug mode, I don't care about runtime stuff and warnings. And in the last line I simply take my dlls and copy then into output folder. Job done.
–
In conjunction with the above answer:
I've got this working great in the Post-build event command line: in Visual Studio.
It loops over a selection of dlls (System*.dll and Microsoft.dll)*, and then skips the deletion of specific dlls. System.Data.SqlClient.dll and 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
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.