BACKGROUND
I have created an ASP.NET webforms (4.6) website that has some 3rd party components in it. In order for this to work I have created a SharedResources folder that contains the DLLs needed. I've added a reference and those DLLs get copied to the BIN when publishing - GREAT. BUT there are some other DLLs needed that cannot be referenced as they are not valid assemblies or COM components.
MY PROBLEM
How can I add to the build, dll's that are in a folder (SharedResources\3rdParty) so that when I click 'Publish' it dumps all those dll's into the bin folder of the website.
WORKAROUND
(trying to avoid this)
I have set the dll Build action to "Content - always copy" and this gives me a folder of DLLs in ~\SharedResources\3rdParty\ and then the application complains of missing dll's so I copy them to the bin manually - that can't be right!
Thanks
Right click your project go to properties and, in the build events tab paste this into your Pre-build event command line: copy $(ProjectDir)SharedResources\3rdParty*.dll $(ProjectDir)$(OutDir)
This will not work when you publish the website. You will have to create your own targets in the project file or a separate targets file and call as follows -
Add following -
<ItemGroup>
<ThirdPartyDllDependencies Include="$(SolutionDir)..\..\Lib\ThirdPartyDll\*.dll" SkipUnchangedFiles="true" />
</ItemGroup>
<Target Name="PublishThirdPartyDllDependencies">
<Copy SourceFiles="#(ThirdPartyDllDependencies)" DestinationFolder="$(OutDir)\" />
<Copy SourceFiles="#(ThirdPartyDllDependencies)" DestinationFolder="$(WebProjectOutputDir)\bin\" />
</Target>
<!-- This target is responsible for adding the ThirdPartyDll and dependencies to the bin directory while Publishing the website. -->
<Target Name="CustomCollectFiles">
<ItemGroup>
<_CustomFiles Include="$(SolutionDir)..\..\Lib\ThirdPartyDll\ThirdPartyDll11\64Bit\*.dll" />
<FilesForPackagingFromProject Include="%(_CustomFiles.Identity)">
<DestinationRelativePath>$(WebProjectOutputDir)\bin\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
<DestinationRelativePath>$(OutDir)\%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
CustomCollectFiles;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
Related
[
<Target Name="AfterBuild" Condition="'$(Configuration)' == 'Release' ">
<CreateItem Include="#(ReferencePath)" Condition="'%(CopyLocal)'=='true'">
<Output ItemName="IlmergeAssemblies" TaskParameter="Include" />
</CreateItem>
<PropertyGroup>
<ReferenceAssemblies>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2</ReferenceAssemblies>
<ILMergePath>..\packages\ILMerge.3.0.41\tools\net452</ILMergePath>
<NugetPackagesPath>..\packages</NugetPackagesPath>
</PropertyGroup>
<ItemGroup>
<dependency Include="$(nugetPackagesPath)\Newtonsoft.Json.12.0.3\lib\net45" />
<dependency Include="$(nugetPackagesPath)\AutoMapper.10.1.1\lib\net461" />
<dependency Include="$(nugetPackagesPath)\RestSharp.106.11.7\lib\net452" />
</ItemGroup>
<PropertyGroup>
<ReferenceAssemblies>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2</ReferenceAssemblies>
</PropertyGroup>
<Exec Command=""$(ILMergePath)\ILMerge.exe" #(dependency->'/lib:"%(FullPath)"', ' ') /out:#(MainAssembly) /targetplatform:v4,"$(ReferenceAssemblies)" "#(IntermediateAssembly)" #(IlmergeAssemblies->'"%(FullPath)"', ' ')" />
<Delete Files="#(ReferencePath->'$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)')" />
</Target>`]
1`Thema: ILMerge packages more dlls under one, but when using this one dll in other programs the hidden dlls are still visible, which leads to version conflicts.
Problem:
Hello I have the following problem with ILMerge:
I[enter image description here][2] have two programs. With program 1, ILMerge runs successfully and it actually packages all dlls under my (one) Service.dll. AutoMapper.dll, NewtonsoftJson.dll are also packaged under Service.dll. This is how my release folder looks after the ILMerge execution(see on the picture << Before ILmerge.exe & After ILMerge.exe >>). Everything seems fine. I package program 1 as NuGet and would like to include this in program 2. Everything looks fine in NuGet Manager, too. There are no other dependencies to be seen with Service.dll.I mean, it shows "no dependencies" in the NuGet-Install window for my Nuget(with service.dll)->(see the picture << Add Reference Service.dll >>) .
But after the "Build Solution" I get an error message that e.g. AutoMapper exists in both (in program 2 where I want to add men Serice.dll and even with Service.dll). NewtosoftJson also causes problems like "found conflicts between different versions of Newtonsoft.json".
Question: Why are the dependencies hidden under Service.dll visible for program 2? How can I solve this problem? I want to use the same dlls such as Automapper.dll in both program 1 and program 2.
Befor/AfterILMerge.exe & Add Reference Service.dll as Nuget
I am using Visual Studio 2019 and creating NuGet packages successfully with this method:
https://learn.microsoft.com/en-us/nuget/quickstart/create-and-publish-a-package-using-visual-studio?tabs=netcore-cli
All going well, but there are some settings (.json) files contained within a directory PageSettings/
When I publish my NuGet package and then install it into a new project, this directory appears in VS as a linked item (see pic). So as a user I can access the files, but they don't "exist" when the project is run.
This means if I run this project without physically copying and adding these files I get ArgumentException: The directory name 'Path-To-project\pagesettings' does not exist. (Parameter 'Path')
I can see why this is happening, but can't work out how to change it, or if it is possible.
The article linked above suggests adding code to the csproj file like:
<ItemGroup>
<Content Include="readme.txt">
<Pack>true</Pack>
<PackagePath>\</PackagePath>
</Content>
</ItemGroup>
But that doesn't work and in fact seems unnecessary since the Pack command is including my files, just not creating them properly when installing.
Also - it would be extremely handy if there was a way to tell VS to prompt whether to install this file or not. Since it is settings, if a user changes the settings and then later installs an updated version of my NuGet package I would not want it to overwrite their customised settings... perhaps this is why the link design happens... if so, if someone could confirm?
Actually, you should create a .props file in your nuget package.
1) create a file called <package_id>.props file in your nuget project.
Like this:
Note: if your created nuget package called test.1.0.0.nupkg, the file should be named as test.props so that it will work.
2) add these in the test.props file:
<Project>
<Target Name="CopyFiles" BeforeTargets="Build">
<ItemGroup>
<File Include="$(MSBuildThisFileDirectory)..\Pagesettings\*.*"></File>
</ItemGroup>
<Copy SourceFiles="#(File)" DestinationFolder="$(ProjectDir)Pagesettings"></Copy>
</Target>
</Project>
3) add these in xxx.csproj file:
<ItemGroup>
<None Include="Pagesettings\*.*(the json files' path of your nuget project)" Pack="true" PackagePath="Pagesettings">
</None>
<None Include="build\*.*" Pack="true" PackagePath="build"></None>
</ItemGroup>
then reapck your project.
4) then clean your nuget caches or delete all files under C:\Users\xxx(current user)\.nuget\packages.
5) when you insall this new version of the nuget package, please build your main project again to run the target to generate the files.
Besides, there is also a similar issue about this.
In my .csproj file, I am creating directories containing files, and these directories are being created in the main project directory as intended. For certain reasons, I cannot generate these directories in bin\debug. However, I do not want the files generated in the directories to be included in the project, as I do not want them to be checked in.
How can I exclude the files from my project automatically through msbuild?
For reference, I have tried the following, and though the files get generated as expected, they are still being added to the project unintentionally:
<Target Name="BuildThings" AfterTargets="Build" BeforeTargets="GatherStagingFiles" Inputs="#(Compile)" Outputs="$(GeneratedFilesDirectory)">
<Exec WorkingDirectory="$(MSBuildProjectDirectory)" Command="$(ToolPath) buildpackage -InputDir:$(MSBuildProjectDirectory)\$(OutDir) -OutputDir:$(MSBuildProjectDirectory)\$(GeneratedFilesDirectory)" />
</Target>
<Target Name="HideFiles" DependsOnTargets="BuildThings">
<ItemGroup>
<GeneratedFiles Include="$(MSBuildProjectDirectory)\$(GeneratedFilesDirectory)\file.txt">
<InProject>false</InProject>
</GeneratedFiles>
</ItemGroup>
</Target>
I have a class library that is referenced by many other web application projects. It has many settings in its app.config that I wish to use in all of the referencing web projects. When the class library is built, it copies the app.config to its own bin folder as <assembly.name>.dll.config.
How do I ensure that <assembly.name>.dll.config is copied to the bin folder of each of my referencing web application projects?
Visual Studio / MSBuild does not seem to do this by default.
Changing Copy to Output Directory or Build Action (in any combination) does not work.
SlowCheetah VS extension appears to do what I want as an unintended side-effect of its config transform process, but I want to do this without any 3rd-party extensions.
As an aside: It's impractical to manually put all of this config in each of the web application projects. I can read the file by looking for <assembly.name>.dll.config in the bin folder, and extract the settings from there. I can already do this, so that's not an issue - I just need to ensure the file is going to be there for reading
This can be achieved without 3rd-party tools by adding the following to the class library's project file, assembly.name.csproj:
// Find this <Import> element for Microsoft.CSharp.targets
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
// Add this <ItemGroup> element immediately after
<ItemGroup>
<Content Include="app.config">
<Link>$(TargetName).dll.config</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
This causes the app.config to be copied to whichever project is referencing it as <assembly.name>.dll.config. It's good because you only need to configure the one .csproj file and the effect cascades out to all referencing projects.
Visual Studio 2015 and earlier
For Visual Studio 2015, I am using the solution of #theyetiman (see this answer):
<ItemGroup>
<None Include="app.config" />
</ItemGroup>
<ItemGroup>
<None Include="app.config">
<Link>$(TargetFileName).config</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
(The import of Microsoft.CSharp.targets was already present.)
Visual Studio 2017
During my experiments, Visual Studio 2017 seems to handle configuration files as expected out of the box. No manual modification of the project file is needed.
I have a C# project that uses the Project Dependencies in a sln file to make sure that the build order is correct.
So I have in my sln file that ProjectB depends on ProjectA.
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProjectB", "ProjectB.csproj", "{E24EAC46-1563-4E73-9411-3F9D2645F77C}"
ProjectSection(ProjectDependencies) = postProject
{4A7D6720-4AA1-4F0B-A796-A0436DB3D7D7} = {4A7D6720-4AA1-4F0B-A796-A0436DB3D7D7}
EndProjectSection
EndProject
ProjectA has some content that is set to CopyIfNewer.
When I build this with Visual studio, ProjectA goes to its own bin folder and ProjectB goes to its own bin folder.
But when I build it with MSBuild, the content of ProjectA somehow appears in the output folder in ProjectB as well!
The build log shows that [ProjectB.csproj] _CopyOutOfDateSourceItemsToOutputDirectory copies the files over.
My question is: How can I tell MSBuild that the files do not belong to that project and don't have to be copied?
As a workaround I added ProjectA as a ProjectReference with <Private>False</Private> and that seems to work, but it is not my desired solution.
I think that the workaround you have described is currently the best solution you can find today.
As a workaround I added ProjectA as a ProjectReference with False and that seems to work, but it is not my desired solution.
I Solve this trouble overriding MSBuild Task in ProjectB .csproj file.
(I have only dependency on ProjectA in .sln file, not adding project as ProjectReference to ProjectB)
Add this targets to your .csproj file:
<Project>
.....
<Target Name="_CopyOutOfDateSourceItemsToOutputDirectory" Condition=" '#(_SourceItemsToCopyToOutputDirectory)' != '' " Inputs="#(_SourceItemsToCopyToOutputDirectory)" Outputs="#(_SourceItemsToCopyToOutputDirectory->'$(OutDir)%(TargetPath)')">
<Message Importance="Normal" Text="$(MSBuildProjectName) Skip copy _CopyOutOfDateSourceItemsToOutputDirectory" />
</Target>
<Target Name="_CopyOutOfDateSourceItemsToOutputDirectoryAlways" Condition=" '#(_SourceItemsToCopyToOutputDirectoryAlways)' != '' ">
<Message Importance="Normal" Text="$(MSBuildProjectName) Skip copy _CopyOutOfDateSourceItemsToOutputDirectoryAlways" />
</Target>
</Project>
For myself files, needed to copy to output directory i do it by XCOPY in postbuild like:
<PropertyGroup>
<PostBuildEvent>xcopy "$(ProjectDir)SomeSubFolder\SomeContentFile.cfs" "$(TargetDir)SomeSubFolder\" /Y /F</PostBuildEvent>
</PropertyGroup>
Maybe there are has smart variant of overriding _CopyOutOfDateSourceItemsToOutputDirectory* tasks like this. But my variant satisfied me now. Because i dont have dependency of other content files in my project.