I'm using CopyToPublishDirectory in my .csproj to copy over files/folders when publishing my dotnet app:
<None Update="Views\**\*; wwwroot\**\*">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</None>
Is there a way to copy over a folder and change its name in the process? For example, I'd like to copy over a subset of my node_modules folder, so I could create a new folder called node_modules_dev with my subset of npm dependencies, and copy it over via CopyToPublishDirectory as node_modules. I'd imagine the syntax would work something like this:
<None Update="node_modules_dev/**/*" Rename="node_modules">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</None>
Thanks--
The trick here is to:
Ensure that the items are not yet included by default so there is no leftover metadata from previous glob pattern expansions. This can be done by adding the path to the DefaultItemExcludes property so the web sdk will ignore the files.
Use the %(RecursiveDir) metadata that is available for items expanded via glob patterns and represents the value of any expanded path. This will be defined for the Include="…" syntax only hence 1.
This will overwrite the default target path to a new directory using the Link metadata:
<PropertyGroup>
<DefaultItemExcludes>$(DefaultItemExcludes);node_modules_dev\**</DefaultItemExcludes>
</PropertyGroup>
<ItemGroup>
<Content Include="node_modules_dev\**\*" Link="node_nodules\%(RecursiveDir)%(FileName)%(Extension)" CopyToPublishDirectory="PreserveNewest" />
</ItemGroup>
Related
I am trying to create a NuGet package that can contain and deploy third party dependencies, these are dll's and executables that my program needs to run. There are a few caveats to this issues though.
When installing the package the dlls need to be in one directory above the bin folder, I can already make them install into the bin folder thats not what I need. (This makes this question different than others I have found)
I would prefer using the packing via the .csproj file instead of the .nuspec if possible.
If I can't place them one level up I could probably make this work installing them into a folder within the bin folder. These requirements are a little weird but I'm a bound by work that has already been done and don't have power to change it.
A small example of one of the many things I have tried:
<Content Include="x86\SQLite.Interop.dll">
<buildAction>Embedded Resource</buildAction>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<copyToOutput>true</copyToOutput>
<PackagePath>lib</PackagePath>
<PackageOutputPath>..\SQLite</PackageOutputPath>
<Pack>true</Pack>
</Content>
Use this:
<ItemGroup>
<Content Include="x86\SQLite.Interop.dll">
<buildAction>Embedded Resource</buildAction>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<copyToOutput>true</copyToOutput>
<PackagePath>lib\$(targetframework)</PackagePath>
<Pack>true</Pack>
</Content>
</ItemGroup>
<PropertyGroup>
<PackageOutputPath>..\SQLite</PackageOutputPath>
</PropertyGroup>
Then, re-pack your project. Before you install this new version, please delete all old nuget caches under C:\Users\xxx\.nuget\packages, then reinstall the new version. After that, re-build your main project and then you will get what you want.
Update
Try to pack the files into content node:
<ItemGroup>
<Content Include="x86\SQLite.Interop.dll">
<buildAction>Embedded Resource</buildAction>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<PackageCopyToOutput>true</PackageCopyToOutput>
</Content>
</ItemGroup>
Then, right-click on the Project-->Pack. And you should not use any other nuspec file to pack with.
I have a NuGet package with a .bond file. Users of my package can derive their Bond structs from the structs in my package's .bond file.
I want the user's Bond files to be compiled when they include my NuGet package. Today they must include my NuGet and the Bond.CSharp NuGet. But, my NuGet already has a reference to Bond.CSharp.
How can I author my package so that the consumers do not need to have their own <PackageReference Include="Bond.CSharp" ... />?
Bond codegen is run from the Bond.CSharp's build targets.
By default, the build targets of packages you consume do not flow to your consumers. The default value of a PackageReference's PrivateAssets is "contentfiles;analyzers;build".
You can override this behavior in your csproj's PackageReference:
<ItemGroup>
<PackageReference Include="Bond.CSharp" Version="[9.0.3]">
<!-- removing "build" from default so that consumers also run codegen -->
<PrivateAssets>contentfiles;analyzers</PrivateAssets>
</PackageReference>
</ItemGroup>
I assume you are compiling the base struct into an assembly in your package. Bond codegen assumes that the generated code and the runtime library exactly match, so I've used an exact match version bound in the PackageReference: [9.0.3]
You said that you want your consumers to be able to derive from your Bond structs, so you'll probably also want to configure their BondImportPath to include the .bond file inside your package. To do this, you need to
make sure the .bond files are included in the package and
add a package .props file to set the BondImportPath to the package directory with said .bond files.
The make sure the .bond files are included in the package, add something like this to your package's .csproj file:
<ItemGroup>
<None Include="bond/**">
<Pack>true</Pack>
<PackagePath>build/bond/</PackagePath>
</None>
</ItemGroup>
This assumes that your .bond files live in a bond\ subdirectory.
To automatically add something to BondImportPath, you need to add a package .props file that will be automatically imported by consumers. Create a file named ExactNameOfPackage.props with the following content:
<Project>
<ItemGroup>
<BondImportDirectory Include="$(MSBuildThisFileDirectory)bond" />
</ItemGroup>
</Project>
This .props file also needs to be packed. Add this to your project's .csproj file:
<ItemGroup>
<None Include="ExactNameOfPackage.props">
<Pack>true</Pack>
<PackagePath>build/</PackagePath>
</None>
</ItemGroup>
Now, the consumer can just use a PackageReference. Any .bond files in their project will be compiled automatically, and they can use import "you-file.bond" to refer to a .bond file in your package.
Build assets do not flow transitively. The NuGet 5+ buildTransitive feature looks like it solves this, but I haven't experimented with it.
Here are the complete project files I used. The complete code is in my GitHub repository, export-bond-file-nuget.
lib-with-bond.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<PackageId>LibWithBond</PackageId>
<Version>1.2.0</Version>
</PropertyGroup>
<ItemGroup>
<None Include="LibWithBond.props">
<Pack>true</Pack>
<PackagePath>build/</PackagePath>
</None>
<None Include="bond/**">
<Pack>true</Pack>
<PackagePath>build/bond/</PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Bond.CSharp" Version="[9.0.3]">
<PrivateAssets>contentfiles;analyzers</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project>
LibWithBond.props
<Project>
<ItemGroup>
<BondImportDirectory Include="$(MSBuildThisFileDirectory)bond" />
</ItemGroup>
</Project>
consume-lib.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<!-- I had a local NuGet source pointing to the output of running
`dotnet pack` on lib-with-bond.csproj -->
<PackageReference Include="LibWithBond" Version="1.2.0" />
</ItemGroup>
</Project>
I was able to make this work for a PackageReference. My initial experiments making it work for ProjectReference were not successful, and I ran out of time to work more on this answer.
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.
I am migrating an old .NET Framework csproj to dotnet core. What is the dotnet core equivalent of this:
<Compile Include="ServiceHost.Designer.cs">
<DependentUpon>ServiceHost.cs</DependentUpon>
</Compile>
I tried:
<ItemGroup>
<Compile Include="ServiceHost.Designer.cs">
<DependentUpon>ServiceHost.cs</DependentUpon>
</Compile>
</ItemGroup>
But I got this error:
Duplicate 'Compile' items were included. The .NET SDK includes
'Compile' items from your project directory by default. You can either
remove these items from your project file, or set the
'EnableDefaultCompileItems' property to 'false' if you want to
explicitly include them in your project file. For more information,
see https://aka.ms/sdkimplicititems. The duplicate items were:
'ProjectInstaller.Designer.cs';
'ServiceHost.Designer.cs' TestWindowsService C:\Program
Files\dotnet\sdk\2.1.4\Sdks\Microsoft.NET.Sdk\build\Microsoft.NET.Sdk.DefaultItems.targets
Since the items are included by default, you need to use Update instead of Include if you only want to modify the items that need this update and not list every cs file individually:
<ItemGroup>
<Compile Update="ServiceHost.Designer.cs">
<DependentUpon>ServiceHost.cs</DependentUpon>
</Compile>
</ItemGroup>
New format SDK projects have several globbing patterns set by default to "True". One of them is to include all *.cs files in project directory and it's subdirectories. The error you are getting is caused by double inclusion of *.cs files and there is an easy way to prevent it indicated in error message. You should include into your project the following property:
<PropertyGroup>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
</PropertyGroup>
With that setting you have to include all files in the project explicitly by using:
<ItemGroup>
<Compile Include="ServiceHost.Designer.cs">
<DependentUpon>ServiceHost.cs</DependentUpon>
</Compile>
<Compile Include="MyOtherFile.cs"/>
.......
</ItemGroup>
If you decide to not use EnableDefaultCompileItems setting all *.cs files will be included automatically, however, their grouping could be confusing as it may be flattened without any subgroupings. In this case you should not include any *.cs files eplicitly in the .csproj. The globbing pattern used by project will include files in the project automatically for you.
In my C# project I have some .docx,.xlsx,*.jpg files in an folder, I want to make all these files as Content and while Setup and Deployment Project I want to add all these files as Content Output for That I have done follwing steps:
Unload Project from property window and then selected to Edit .csproj file.
Added below lines in <ItemGroup> to make all files in folder as Content and linked them to a folder
<Content Include="Lib\MyApp\Support\**\*.*">
<Link>Support\%(RecursiveDir)%(FileName).%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Lib\MyApp\Files\**\*.*">
<Link>Files\%(RecursiveDir)%(FileName).%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
Reload Project
After reloading project I got lots of warning like
Warning 34 The file 'Lib\MyApp\Files\abc.bmp' could not be added to
the project. Cannot add a link to the file
D:\MyApp\Lib\MyApp\Files\abc.bmp. This file is within the project
directory tree.
I have Excluded the Lib folder from project, Why I am getting such warnings what I am doing wrong? Is it safe to ignore such warnings.
Update
After modifying csproj file to this
<Content Include="Lib\QOES\Support\**\*.*">
<Link>Support\%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>false</Visible>
</Content>
<Content Include="Lib\QOES\Files\**\*.*">
<Link>Files\%(RecursiveDir)%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>false</Visible>
</Content>
after adding <Visible>false</Visible> removed warnings, but is this correct way?
Adding <Visible>false</Visible> seems to be a very convenient solution to get rid of the Visual Studio warning:
The file <filename> could not be added to the project. This file is
within the project directory tree.
According to: MSDN: The file 'file' could not be added to the project, one of the reasons is relative paths being ambiguous. Meaning you have the file path Lib/MyApp/Files/abc.bmp both as a file path in your project folder as well as on your D: drive leading to ambiguity. That is my guess. Adding files by hand to the project folder can lead to issues.
In my case where I wanted to place a native binary aside of the executable, using <TargetPath> instead of <Link> worked:
<Content Include="Lib\somelibrary.dll">
<TargetPath>somelibrary.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>