I wrote a class library in C# that I need to push to a private NuGet server (v3.4.1.0). I decorated my classes and methods with XML documentation comments.
XML documentation file option is checked on the Build tab of the project properties panel, the project builds successfully and the xml file gets generated on the project's root folder with the same name as the assembly.
In the .csproj file the related section looks like this:
<PropertyGroup>
<DocumentationFile>absolutePathTo\assemblyName.xml</DocumentationFile>
</PropertyGroup>
IntelliSense (VS2019 16.9.0) recognises the documentation and shows it properly even in other projects under the same solution.
When I generate the NuGet package it gets created in the project's bin\Debug folder. If I open it as a zip archive the DLL and the documentation XML can be found in the lib\netstandard2.1 folder having matching names.
Once I install this package to another project from the private NuGet server it works properly but loses the complete documentation. IntelliSense does not show my comments anymore and the assembly metadata seems not to have it either.
Could anyone support me on this one?
That is normal. For xml document, it is special under new-sdk style projects. The xml document could only be copied into the non-sdk net framework projects but new-sdk net core projects cannot. More similar to this issue I handled before.
So you should try these steps additionally to get what you want:
1) enter these node under csproj file of your nuget project.
<ItemGroup>
<None Include="xxx\absolutePathTo\assemblyName.xml"(the path of the xml file under your project folder) Pack="true">
<PackageCopyToOutput>true</PackageCopyToOutput>
</None>
</ItemGroup>
2) after that, re-pack your nuget project and before you install the new version, please clean nuget caches first or just delete all files under C:\Users\xxx\.nuget\packages
Personally, I let Visual Studio handle things for me.
If you right-click in the project, and choose Properties,
In the Build -> Output area, you should see a checkbox under Documentation file labelled Generate a file containing API documentation..
When you check this, a new option appears underneath: XML documentation file path. But the file selector is labelled Optional path for the API documentation file. Leave blank to use the default location..
FYI: The default location is alongside your EXE / DLL that is generated when you build your project.
When you next build your code (for anyone else reading, I assume you've got the Generate NuGet package on build in the Package area checked too) it will also package up the XML documentation into the NuGet package generated.
From the perspective of users of this new package, Visual Studio will pick up on the XML Documentation inside.
Related
I am trying to get my head around how Nuget works when creating packages and must admit that I cannot grasp it.
To generalize my task, it is to include a file in the Nuget package, create that Nuget package and when installed as a dependency in other project, the file is shown there in the project structure or somewhere to be manipulated with.
This file is a central .DotSettings file which would then propagate to all the C# repositories and solutions.
Where I am now
I have a .dll project, I have my content folder where the file is and I specify that within the .csproj file as such:
<ItemGroup>
<Content Pack="True"
PackagePath="\"
Include="content\test.DotSettings" />
However, when this is Nuget packed and this dependency is installed in another project, I cannot see this file in the project/dependencies/packages folder, where I would like it to be (and I suppose it should be there, right?)
The workaround I have now is that I reference this file from within the users/nuget/packages folder, however, I do not fancy this solution that much.
So, the main question:
Is there a way to copy the file so that when the dep is installed, the file is shown at the top level project folder structure? if so, what am I missing?
misc questions:
As I understood it, I can write my own .nuspec file and specify it there somehow, but when I did that, at build it always overrides it with its own autogenerated .nuspec file. Is this a wrong way to take at all and should I not create my own .nuspec?
What about the .target and .props file, what is that for and do I need to bother with those in my task or not at all? From what I understood, I should be good with my .csproj file and be able to define it all within it.
TIA!
I have two class libraries in a single solution (.NET Core). One of them (cl1) is a main library and it depends on another library (cl2). I have added a .nuspec file with the required metadata only (no dependencies, no files) for the cl1 project in the project folder (same location of .csproj file) and I have set GeneratePackageOnBuild propery to true.
Whenever I am building the class library (cl1), the .nupkg is created automatically in the debug/release folder.
When I check the generated .nupkg file, I am see two strange things:
The generated .nuspec file is different than what I have added in the project folder
cl2 is mentioned as a dependency in the newely generated .nuspec file, but the DLL for cl2 is not included in the lib folder of the .nupkg. So, whenever I consume this package in another solution, I am getting the error No packages exist with this id in source(s) for the cl2.
I have surfed in internet, but was not able to find a proper solution for the above error.
And I have added a .nuspec file [...] in the project folder(same location of .csproj file)
You have to specify the path to your own NuSpec file in the .csproj using the NuspecFile tag, otherwise it will be ignored and the package will be created with the metadata from the .csproj file instead, see reference. You need to use either a relative or an absolute path to the file, for example:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<NuspecFile>cl1.nuspec</NuspecFile>
</PropertyGroup>
</Project>
The generated .nuspec file is different than what I have added in the project folder
As already stated, your NuSpec file is probably not included. However, even if it is, there can be differences, because some information, e.g. source file locations are unnecessary and the target locations are in most cases given by the internal package file structure itself, so it is not there because it is redundant.
cl2 is mentioned as a dependency in the newely generated .nuspec file, but the dll for the cl2 is not included in the lib folder of the .nupkg. So, whenever I consume this nupkg in other solution, I am getting error " No packages exist with this id in source(s)" for the cl2.
Dependencies are meant for packages. So when NuGet restores the package it searches for other packages that this package depends on, here cl2, but there is none, hence the error. When packing a project, referenced projects are not included in the package. That is an open issue and there are workarounds that you can try.
The most reliable, but inconvenient solutions are to avoid the issue at all.
Only use a single project, everything will be included in the package
Pack each project on its own and use the generated package instead of the referenced project
Recently upgraded an old version of an open source project. The new project file is is the newer SDK project type, and i'm having a problem with something that should be super simple.
When building the old project, the output files were copied directly into the folder I specified in the project properties, build tab, "Output Path" field. Which I specified as either bin\x64\Debug or bin\x64\Release depending on the Configuration.
With this new project format, however, the actual DLLs are output into bin\x64\Debug\net461 instead. If I change the target framework, the output file is in a different location. bin\x64\Debug\net462 for instance.
I need it to never copy to the framework subdirectory. It royally screws up the nmake build scripts we use. How do I fix this?
What's more, the build directory is FULL of useless dependency DLLs copied from God knows where. I don't want anything in the output directory except the output.
How do I go about making this new project format work like the old one?
Add it to your csproj
<PropertyGroup>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
</PropertyGroup>
AppendTargetFrameworkToOutputPath controls framework name
AppendRuntimeIdentifierToOutputPath controls x64/x86
Intro (how to pack resources into a nuget package)
To pack some resource files into a nuget package, what one would normally do, is the following.
Put all the resource files into the content\ directory of a nuget package. This would be specified by the following line in a .nuspec file:
<files>
<file src="Project\bin\Release\script.js" target="content\js\script.js" />
<files>
Now, when this nuget package gets installed into AnotherProject, the following file structure emerges:
Solution.sln
packages\Project.1.0.0\content\js\script.js // the original resource file
AnotherProject\js\script.js // a physical copy
AnotherProject\AnotherProject.csproj // <Content /> tag (see below)
During package installation, AnotherProject.csproj was injected with tag:
<Content Include="js\script.js" />
and this is for the physical copy of the original resource (which is under packages\ directory).
The actual problem (how to pack resources into a nuget package as link)
My aim is not to have the physical copy of a resource file in the AnotherProject directory but rather a "link" to the original resource under packages\ directory. In the csproj, this should look like this:
<Content Include="packages\Project.1.0.0\content\js\script.js">
<Link>js\script.js</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
Brute force solution that I would rather avoid
Now, one "do it the hard way" workaround I can think of is:
not putting resource files under content\ so they do not get added automatically,
writing Install.ps1 script that would hack the csproj file structure and add the necessary XML piece manually,
This, however, has the following drawbacks:
all my nuget packages need the same script piece in their Install.ps1,
when installing my packages, there would be a nasty "project reload prompt" in Visual Studio.
Since NuGet currently does not support this out of the box your options are either to use PowerShell or to use a custom MSBuild target.
PowerShell
Leave your resources outside of the Content directory in your NuGet package (as you already suggested).
Add the file link using PowerShell in the install.ps1.
You should be able to avoid the project reload prompt if you use the Visual Studio object model (EnvDTE). I would take a look at Project.ProjectItems.AddFromFile(...) to see if that works for you.
MSBuild target
NuGet supports adding an import statement into a project that points to an MSBuild .props and/or .targets file. So you could put your resources into the tools directory of your NuGet package and reference them from a custom MSBuild .props/.targets file.
Typically the custom .props and .targets are used to customise the build process. However they are just MSBuild project files so you could add items for your resources into these project files.
Note that .props are imported at the start of the project file when a NuGet package is installed, whilst .targets are imported at the end of the project.
Customising NuGet
Another option, which would take more work, would be to modify NuGet to support what you want to do.
I'm building a NuGet package that delivers some T4 templates into the CodeTemplates directory. When I install the NuGet package, the T4 templates all have the Custom Tool property set to "TextTemplatingFileGenerator". This isn't right.
I know I can disable this by altering my registry so that new T4 templates aren't added this way, but since this is a NuGet package, that is not an option.
I've looked into PowerShell, but I'm having trouble understanding what I would do to achieve my goal.
I've looked at the .csproj file xml and found this:
<None Include="CodeTemplates\AddController\Controller.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Controller.cs</LastGenOutput>
</None>
If I remove "TextTemplatingFileGenerator" from this node, then the file will work as I desire.
Where should I go from here?
I'm not sure there's a nice way to do this. In a blog post, David Ebbo wrote:
One last thing I’ll mention about this
model is that the .tt file is normally
not part of your project. Instead, it
lives somewhere else, and only its
output becomes part of your project.
Well, technically, the .tt file can be
in your project for easy editing, but
you then have to remove the
‘TextTemplatingFileGenerator’ custom
tool, because you really don’t want it
to execute on its own (it would surely
fail with the custom host).
This makes it sound like this is Visual Studio behavior when a .tt file is added to the project.
That said, Scott Hanselman's AddMvc3ToWebForms makes some changes to a GUID in the csproj file to add MVC functionality (Add Controller / Add View, etc.), so it's possible you could do something similar to his code and remove the Generator section for files in your package and reload the project?
I had the same problem and I solved it using "install.ps1" which executes everytime the nuget package is installed or updated.
Your install.ps1 should look like:
param($installPath, $toolsPath, $package, $project)
$addControllerFolder = $project.ProjectItems.Item("CodeTemplates").ProjectItems.Item("AddController")
$addControllerFolder.ProjectItems.Item("Controller.tt").Properties.Item("CustomTool").Value = ""