NuGet package contentFiles artifacts installed as links in ASP.NET Core MVC project - asp.net-core

We have an internal JavaScript library that we'd like to share between multiple projects. Actually we are already sharing it via file copying, but this has (predictably) resulted in multiple forks of the code.
The consuming projects are a mix of "full" ASP.NET (MVC and Web Forms) and ASP.NET Core MVC. (I'm planning on creating two separate packages.)
Installing into ASP.NET projects seems to work fine, but I'm having problems with ASP.NET Core.
Initially I had all the artifacts within a files element, and nothing at all was showing up in the consuming project. After re-reading the docs, I realized that ASP.NET Core projects would use a PackageReference ... so I would have to use a contentFiles element instead of (or in addition to) a files element.
I created a contentFiles folder and a script to copy the requisite files from the source project folder structure into contentFiles/any/any/wwwroot/lib/ourAwesomeWidget, and modified the package manifest accordingly.
This works. Sort of. The package appears to get build correctly. The files do get added to the consuming project, but they get added as links; the actual files (the link targets) reside in my local package cache.
The relevant portion of the package manifest is:
<metadata minClientVersion="3.3">
...
<contentFiles>
<files include="**/*" buildAction="Content"
copyToOutput="true" flatten="false" />
</contentFiles>
</metadata>
<files>
<file src="contentFiles\**" target="contentFiles" />
</files>
Part of the issue is that I don't find the docs very clear concerning contentFiles. All the examples show a single file element ... but the include attribute on the files element is required, so it's not clear what the individual file elements would even do.
Is there a way to get the actual files (not links) added to the consuming project? Or, alternatively, is there a way to get the package to install as a "normal" package (rather than a PackageReference)?
Update:
I did some further digging and found this answer by #Martin to a similar question -- but he answered this one before I had a chance to update it.
It appears this behavior (adding files as links) is by design.
I find this highly unsatisfactory, because (as #Martin points out), our JavaScript library will not be available during development on consuming projects.
But part 2 of my question still stands. According to the docs,
By default, PackageReference is used for .NET Core projects, .NET Standard projects, and UWP projects targeting Windows 10 Build 15063 (Creators Update) and later.
Is there a way to trigger the non-default behavior, i.e. allow .NET Core projects to consume packages other than via PackageReference?

contentFiles are supposed to be added as a link. The contentFiles section controls the msbuild items that are generated for these files into the obj\projectname.csproj.nuget.g.props file.
The copyToOutput="true" will cause the items to be copied to the output and publish directory. However that does not help you when running the application during development, since it will be run from the project directory, not the output directory.
Consider consuming client libraries via npm (since bower is deprecated).

Related

NuGet package XML documentation not visible in .NET Core 2.2 app

I am using a NuGet package which has an XML documentation file.
But when I include the package in a .NET Core 2.2 app, the comments are not available with IntelliSense.
Is there something I'm missing either in the package or in my app to be able to see the documentation with IntelliSense?
Using VisualStudio 2017, Windows 10.
Update for Clarity
The NuGet package is a .NET Standard 1.3 class library. In Visual Studio when I build the project, I include the options to generate the package and documentation file. In the project file, I see the following PropertyGroup:
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DocumentationFile>C:\Users\[username]\[local path]\CommonEntities\CommonEntities\CommonEntities.xml</DocumentationFile>
</PropertyGroup>
When I open the package, I can see in the lib/netstandard1.3/ directory that CommonEntities.xml is included along with MakanalTech.CommonEntities.dll.
But, I'm wondering why the xml file has dropped the full name from MakanalTech.CommonEntities.xml as it is in the project to just CommonEntities.xml in the package. Maybe this is the cause of the issue?
The issue is then when I include the package as a dependency in another project, none of the XML comments/documentation are visible. So I can't hover over a type to see its description, and if I peek definition none of the comments/documentation are in the definition.
Class Library Product
https://imgur.com/zbE7ngM (can't post images yet)
Peeking at definition from other project:
https://imgur.com/pwmvpX7
Finally found the issue from this post. This seems quite buggy from Visual Studio 2017 not to handle this correctly and automatically.
In the .csproj file, I removed <DocumentationFile>[filepath-to-xml]</DocumentationFile> and added <GenerateDocumentationFile>true</GenerateDocumentationFile>.
I then repacked the library, cleared my nuget cache, and rebuilt the new project where it's included, and now I have all the XML documentation visible.
NuGet package XML documentation not visible in .NET Core 2.2 app
Just like what have you found that "in the lib/netstandard1.3/ directory that CommonEntities.xml is included along with MakanalTech.CommonEntities.dll.", the .xml file in the lib folder, then according to the document From a convention-based working directory:
Only the .dll file will be added as reference, .xml file will be copied to the project folder. That is the reason why the XML documentation not visible in .NET Core 2.2 app.
Besides, since you are using .netstandard project, .xml file will blocked be copied to the project folder automatically by the nuget issue 4837.
To resolve this issue, we have to create the .nuspec file with option contentFiles to include the .xml file and add this file to the project, please check the detail info from other thread.
But if you do not want to manually edit the .nuspec every release, you can use a post-build event to pack the nuget package automatically,like:
nuget pack "$(.NuspecFilePath)\xxx.nuspec"
Or you can add the .xml file to the project manually from the package directly, that package is in the path: C:\Users\<UserName>\.nuget\packages.
Hope this helps.

'runtimes' Folder after Publishing a .Net Core App to Azure Publish Via VS Online

What is the purpose of the 'runtimes' folder that gets published along with all my project files? I have a VS Online account, and have the build/deploy process configured through there. The 'runtimes' folder is certainly not a folder that exists in source control or my project folder.
'runtimes' folder contents:
example contents:
Thanks,
Drew
Like #Gregory_Ott I was facing a similar issue where my deployment was an FDD deployment and the 'runtimes' folder was still being created. All I did was, mentioned the runtime and set the self-contained property to false.
In the following example I have used dotnet to publish:
dotnet publish -c Release -o ..\publish --runtime win-x64 --self-contained false
The following link should help you with the deployment:
https://learn.microsoft.com/en-us/dotnet/core/deploying/deploy-with-cli
These exist because you are building your application as a self contained application as opposed to one that is dependent upon the framework being installed on the machine executing it. Documentation can be found at https://learn.microsoft.com/en-us/dotnet/articles/core/deploying/ describing the various options that can be used to control this output.
If portable target runtime is selected, runtime folder is created.
FWIW, I was facing this situation with a .NET 5 application. An empty "runtimes" project was there in the output directory. After wasting a few minutes I realized that the folder was a left-over from a previous build. I deleted bin/obj folders completely and published again and the "runtimes" folder is no longer there in the output. I didn't have to change anything in the project file or build options. Hope it saves someone else a few minutes too.
Could this explain the existence of a runtimes folder in an FDD deployment:
A framework-dependent deployment with third-party dependencies is only
as portable as its third-party dependencies. For example, if a
third-party library only supports macOS, the app isn't portable to
Windows systems. This happens if the third-party dependency itself
depends on native code. A good example of this is Kestrel server,
which requires a native dependency on libuv. When an FDD is created
for an application with this kind of third-party dependency, the
published output contains a folder for each Runtime Identifier (RID)
that the native dependency supports (and that exists in its NuGet
package).
Source: https://learn.microsoft.com/en-us/dotnet/core/deploying/deploy-with-vs?tabs=vs156#framework-dependent-deployment
Setting your RuntimeIdentifier might be the solution. In my case, working with an Azure Function, it cut about 500 megs and reduced my archive down to 174 megs. This is important because on Consumption plans you get very limited storage.
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<LangVersion>preview</LangVersion>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
<OutputType>Exe</OutputType>
<!--
Prevents the runtimes folder from being created in publish, which contained 500 megs of runtime files we don't need.
-->
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
<PublishReadyToRun>true</PublishReadyToRun>
</PropertyGroup>
In the publish profile in Visual Studio, if Target runtime is set to 'Portable' then all possible runtimes are generated. This is the default, so the output can be reduced by a more selective choice if applicable:

TFS Build dropping extra files including csproj in target folder

I have an automated build process set up to run from a build definition in TFS, which publishes a web application and generates/executes a database project script successfully via publish profiles that are passed as msbuild arguments in the build process definition. Everything is now running as expected except that several unnecessary files are being deployed to the target folder, including the .csproj file, all of the config transforms, and the properties folder which contains all of my publish profiles.
This is strange because 1. It's definitely not including ALL files/folders and mostly appears to be including ones used by the publish profile like transforms, while applying the transform correctly and excluding any explicitly excluded file (as defined in the pubxml), and 2. The process works perfectly if I do it by publishing from the project in Visual Studio 2013. I have the profile configured to only include files needed by the application, and I've confirmed in the csproj file that this property is there.
I tried excluding the properties folder from deployment in the pubxml file, but this causes the build to crash because it can't find the assembly file. What I've gathered is that the process is keeping all files it needs to complete the build, and dropping all of those files in my destination folder. FWIW, I'm using the "file system" method and I'm not sure yet if web deploy will make a difference. I haven't been able yet to connect to the target server with web deploy, but that's a separate problem to solve. Is there something in the build that I can configure so that my destination folder has only the files it needs to run the application, and not the files needed to BUILD the application?
FYI I also have not been using a drop folder, I'm not sure if that makes a difference or not but that might be the only thing I haven't tested as it doesn't seem necessary since I'm using a publishprofile and don't want to use the default tfs build configuration.
I found a solution that works well enough, after reading this: http://www.asp.net/web-forms/tutorials/deployment/advanced-enterprise-web-deployment/excluding-files-and-folders-from-deployment
This was a little uglier solution than I wanted, since it requires hard-coding the names of excluded files, but it does the trick and only requires identifying the files and folders in one location instead of altering a publish profile for each target environment. I created a wpp.targets file and used the ExcludeFromPackageFolders and ExcludeFromPackageFiles elements to identify the extra files. Ironically, if I don't also name the wpp.targets file in the exclude element, THAT file is included in my package. It's possible MSDeploy doesn't have the same issues with TFS as filesystem, but after spending half a day trying to work through a different set of issues and permissions workarounds, we decided that file system is a cleaner publishing method.

Integrating NuGet into a large, existing code base, with a shared packages directory and a shared solutions directory

Q: Is it possible/feasible, to have a multiple solutions stored in a single 'Solutions' directory, and multiple NuGet packages stored in another single 'Packages' directory, and for everything to work nicely with different versions?
Further details...
For example: I have 2 projects. ProjectA requires Newstonsoft.Json.4.5.11, ProjectB requires Newstonsoft.Json.5.0.6.
For sake of example I have a solution file for both. I need all my solution files in the same directory (this is just the process that is followed, all the solutions in a directory are built in turn).
By default NuGet will create a packages directory alongside each solution file.
I have created a nuget.config file to allow me to store packages in a single directory, called 'SharedPackages', following this answer: Nu-Get & issue with project level dependences for projects referenced by multiple solutions
<settings>
<repositoryPath>..\SharedPackages</repositoryPath>
</settings>
This works great so far, so my structure is:
\Projects\ProjectA
\Projects\ProjectB
\Solutions
\SharedPackages
If I create ProjectB, it has Json.NET 4.5.11 by default. If I go to Manage NuGet Packages for Solution I have the option to update it to version 5.0.6. This is great as ProjectB needs the newer version. What is even better is now in my Shared Packages directory I have a directory for both versions of Json.NET side-by-side, so ProjectA can use the older version.
However, now I want to create ProjectC as a full MVC4 Web Application. For JQuery, you get version 1.8.2 currently when creating an ASP.NET MVC4 application in VS2012. I also get Knockout 2.2.0.
My process is, I delete the default packages directory, move the new solution to the Solutions directory alongside the existing nuget.config and edit the new solution file to update the relative path to the new .csproj file. Then when I build, NuGet Package Manager restores the extra packages I need (that weren't in use by ProjectA and ProjectB) to the Shared Packages directory. However... I get build errors, it cannot resolve some references including DotNetOpenAuth, WebGrease, System.Spatial... the references are pointing to the packages directory, not the SharedPackages directory...
As an aside: if I Enable Package Restore for solution, then it also tries to restore them to a packages folder within the Solutions directory by default, instead of restoring them to the SharedPackages directory.
Around about this point I realise that just creating the nuget.config file wasn't enough for ProjectA and ProjectB either, although they appeared to be working originally, the references in the .csproj. file are pointing to the bin folder beneath the project file, instead of my SharedPackages directory.
So I manually 'Find and Replace' ..\packages with ..\..\SharedPackages for all the references. I have to do this for ProjectA, ProjectB and ProjectC. Now everything builds and seems to work OK, new packages go into the right place.
Now, if I go back to ProjectA, and add the Knockout package, this is version 2.3.0. This installs happily alongside the other Knockout package in use by Project C which is version 2.2.0. Doing this also installs JQuery 2.0.3, alongside JQuery 1.8.2. So far so good.
Just as a sanity check, I create another Web Application - ProjectD, move the files around, update the references in the solution and the project. This time everything builds first time. I try and update WebGrease in ProjectD to see if it will retain the older version for ProjectC. This results in more issues, it installs it to the packages directory instead. WebGrease seems to have a separate config setting as well <WebGreaseLibPath>... it won't seem to restore...
I then go back to ProjectB and try 'Update All' - it looks like the files that already exist are updated in SharedPackages, with new version directories alongside the existing ones, but any new dependencies (e.g. now I have a reference to Owin.dll) get placed in the packages folder :( If I delete the packages folder, and the bin folder within ProjectB, then build the ProjectB solution, understandably I get build errors, the packages aren't automatically restored to the SharedPackages directory at any point.
Is it even possible to set NuGet to update packages in a common directory other than packages alongside the solution?
Would it be easier to just use the default packages folder, instead of SharedPackages, or would I still have problems?
This is turning into way too many questions. To try and keep it in scope, has anyone attempted a similar setup, what obstacles did they overcome and how did they manage it, or did they give up altogether? If you gave up, how did you end up using NuGet to manage packages in a massive code base?
I appreciate this is close to this question, which was well answered for that particular question, however the use case here is slightly different: NuGet and multiple solutions. It is also pretty much identical to this question: Setting up a common nuget packages folder for all solutions when some projects are included in multiple solutions, but I have decided to add this anyway as that question is more focused on the having different configurations for different solutions, whereas here I want all the packages in one place, I just want to implement it and see if it is possible. Also I think the troubleshooting and research time may be useful to someone.

MSBuild overwriting dependencies

Ok, so I've got a somewhat complicated problem with my build environment that I'm trying to deal with.
I have a solution file that contains multiple C# projects which is built by a NAnt script calling MSBuild - passing MSBuild the name of the solution file and a path to copy the binaries to. This is because I want my automated build environment (CruiseControl.Net) to create a folder named after the revision of each build - this way I can easily go back to previous binaries for any reason.
So idealy I have a folder layout like this
c:\build\nightly\rev1
c:\build\nightly\rev2
c:\build\nightly\rev3
...
c:\build\nightly\rev10
etc.
The problem that's arisen is I recently added the latest version of the Unity IoC container to my project, checking it directly out of MS's online SVN repository. What's happening is I have a Silverlight 3 project that references the Silverlight version of Unity but I also have other projects (namely my Unit testing project) that reference the standard (non-Silverlight) version of Unity.
So what happens is since MSBuild is dumping everything into one single folder the Silverlight version of the Unity assembly is overwriting the non-Silverlight version because they have the exact same assembly file name.
Then when CruistControl runs my unit tests they fail because they don't have the proper dependencies available anymore (they try to load the Silverlight specific Unity assembly which obviously doesn't work).
So what I want to do is:
keep my desired output directory
structure (folder\revision)
I don't want to have to manually edit
every single proj file I have as this
is error prone when adding new
projects to the solution
Idealy I would like MSBuild to put everything into a folder structure similar to this:
nightly\revision1\project1
nightly\revision1\project2
nightly\revision1\project3
...
nightly\revision2\project1
nightly\revision2\project2
nightly\revision2\project3
etc
I can't modify the Unity project to give it a different file name because it comes from another SVN repository I cannot commit changes to. I found a similar question posted here and the suggested solution was to use a "master" MSBuild file that used a custom task to extract all the project file names out of the solution then loop over each one building them. I tried that but it doesn't build them in the order of their dependencies, so it fails for my project.
Help?
Firstly I would always have the build server delete the old working copy and check out a fresh copy to avoid any problems with stale artifacts from the previous build.
Next I would have nant or msbuild build the solutions as before with the artifacts from each build going to their local working output folders.
After that I'd move the artifacts from their working paths to their output paths, this shouldn't require digging through the project files since you can just tell msbuild/nant to copy working\project1\bin\release\**\*.* to artifacts\project1\.
The script that does this should ideally be stored along with the source with the main file, e.g. build.nant or build.proj in top level of the trunk.
For third party libraries I would simple include the DLLs directory in your repository. Nothing worse than writing some code and having a third party dependency break your build because of changes on their end.
Simply document the versions of the libraries you are using, and if you must update them, you'll have a better sense of what breaks the build before you even check it in.
Also, doesn't CC.Net automatically handle the providing of releases based on revision? I'm using TeamCity and it keeps a copy of the artifacts of every build.
I highly recommend reading JP Boodhoo's Automating Builds with NAnt blog series. That's been my starting point and have made lots of changes for my own taste. I also highly recommend checking out the builds of many open sources projects for examples. I've learned a lot from the builds of the Castle/Nhibernate/Rhino-Tools stack.