Shipping msbuild task as nuget - c#

I need your help.
I'm developing an msbuild task that performs certain actions upon msbuild.
I want my users to be able to download and install a nuget package and once the package is installed the build task will be part of the build process.
I know how to release a nuget package and i know how to includes a custom targets file together with the nuget, what i don't know is how to add the import statement to the csproj upon nuget installation:
Is there a way to do so or am i asking for too much?
Thanx!
Gilad

The docs aren't in the easiest to find place, but here's a link to the docs on including MSBuild props/targets files in your package.
Basically, you put the file in the package in the location build\<tfm>\<package_id>.props. For example build\netstandard2.0\MyPackage.props. If you want your build targets to be included in all TFMs, you can use build\<package_id>.props, but if your package also contains other assets like lib/ or contentFiles/, the "no-TFM" build files will cause "asset-target fallback" to fail, so if your package has only net472 libs, and the build files, a project targeting netcoreapp3.0 will get only the build assets, none of the net472 assets. If your build files are in a TFM folder, then NuGet's asset target fallback will select both the lib and build assets. So, I strongly encourage everyone to always use the TFM folder.
The docs need to be improved, but the table explaining lists build, buildTransitive, and buildMultiTargeting. Projects using packages.config only use build assets under build. Projects using PackageReference only use build and buildMultiTargeting assets when the project references the package directly. Assets under buildTransitive get selected when the package is pulled in transitively, rather than directly. The difference between build and buildMultiTargeting is complex. If you understand the concept of "inner-build" and "outer-build" in multi-targeting SDK style projects, that's the difference (build is inner-build), otherwise only use build.
I should update the docs to have this information.

Related

Does nuget create separate packages?

I am still confused about how nuget works. I git clone a C# .sln project and from console, and I ran this nuget command:
nuget restore my_project.sln
it came to my attention that it generates two packages containing all dependencies required by my_project.
One package is located under my_project/src/packages, the other c:/users/my_user_name/.nuget/packages. While the file structures are a little different the DLL files in both packages are identical.
That confused me. Why two packages are generated by default? Where exactly does Visual studio look up for the project's dependencies?
More important, which config file should I update in order to only keep a copy of the dependencies and how can I specify the location in my file system for the packages?
Recent versions of NuGet support package references in project files.
This format will restore packages on demand, using your %USERPROFILE%.nuget folder as a cache. And your solution folder won't be "polluted" by a packages folder with binaries that you probably don't want to commit to source control.
VS2017 allows you to select "PackageReferences" or the older "Packages.Config" format when you create new projects (Tools/Options/NuGetPackageManager/General).
You probably have some projects in your solution that use the older "Packages.config" format, which stores in the packages folder in the solution directory, and newer "PackageReferences" format.
To convert the older projects to the new format, I believe you need to remove all packages from the project, then add them back again. They will be added using the default format you selected, with a prompt for confirmation if you selected "Allow format selection on first package install".

How do i get the NUnit2XmlResultWriter.dll into my project to use it?

I want to write that C# code convert-nunit-3-nunit-2-results-xml-file, but despite the added nuget package i'm missing the dll in my project.
I see it in the tool's directory of the package cache, but missing it in my project.
What do i overlook?
My project is at present for .Net Core 2.1. Is my issue therefore related to this: Add support for net standard ?
I'm new to .net and don't understand all the differences so far.
As zivkan explained, the package is a tool. In fact, it's an extension to another tool, the NUnit engine package. The NUnit engine knows how to find and use the extension.
NUnit does not publish a package that is intended for use by your code as a library, because we would then have to support it as a library in addition to it's use as an extension to NUnit.
However, NUnit's MIT license allows you to use the source code, which you can find at https://github.com/nunit/nunit-v2-result-writer
Since the code has not yet been ported to .NET Core, you would have to do that yourself.
You didn't overlook anything. Not all NuGet packages are libraries.
NuGet has conventions on how files must be packed in order to use various features. For example, files in the content or contentFiles get copied into the project directory, or build output, depending if the project using the package uses packages.config, or PackageReference. If the package author wants to give you a library that you can use in your code, they must put the library in the lib directory in the nupkg (technically it could be in ref, but those don't get copied to build/publish output, they're only used at build time). The tools directory is, unsurprisingly, intended for tools packages. It's often used by unit test runners, or in this case, a report generator.
So, since the package puts the dlls in the tools directory, this means the package author intends the package to be a tool to assist you during development, but not as a library for you to use in your code. You could try contacting the package author to see if they have published another package with the same dll, this time in the lib directory, so that you can use it your project.
Otherwise you'll need to find a solution that doesn't rely on NuGet bringing you this dll as a library. One option is to have a packages.config file that extracts the package in a solution packages directory, and then you use a dll reference to the dll. Your build script would then need to first restore the packages.config file before building your project. Another option is to check in the dll into your source control management tool, if the dll's license allows that, and again have a dll reference to it.

Visual Studio 2017 csproj adds "weird" files on package install

I have some issues with my VS2017 csproj's(https://natemcmaster.com/blog/2017/03/09/vs2015-to-vs2017-upgrade/). When I install certain nuget packages, I'd get some additional files being added to my project and most of the time the dependency is not even working properly. It does not do that on older csproj's.
Two examples:
I have one "home made" nuget (made out of a VS2017 csproj too) which is supposed to transform the local app.config of the target project on install and uninstall (basically adding a line on install and removing it on uninstlal). On a older csproj, it does what it needs to do. With a VS2017 csproj, it will not do the transform but add the two transform files to the projects.
I need to install the package named "CefSharp.OffScreen" on one of my projects. On an older one it works like a charm. On a VS2017 csproj the dependency is not even there (it has a "!" in front) and it adds two "x64" and "x86" directories with tons of files ("dll's" etc.) in there.
Is there something known about issues like that with VS2017 projects ?
Thanks in advance for the help !
Is there something known about issues like that with VS2017 projects ?
For the first example, That because xdt transforms aren't supported in PackageReference environment. This includes both sdk-based projects as well as classic .net framework projects using PackageReference instead of packages.config. You can follow this GitHub issue for more details. There is also a sample package that shows how to use build-time logic to apply transforms instead to work in all environments.
For the second example, you can find a CefSharp.Common.targets file in the \build folder in the dependency package CefSharp.Common, in this .target file, you can see following code:
<ItemGroup>
<CefSharpCommonBinaries32 Include="$(MSBuildThisFileDirectory)..\CefSharp\x86\*.*" />
<CefSharpCommonBinaries64 Include="$(MSBuildThisFileDirectory)..\CefSharp\x64\*.*" />
<CefSharpCommonBinariesAnyCPU Include="$(MSBuildThisFileDirectory)..\CefSharp\**\*.*" />
</ItemGroup>
With this .target file, nuget will including files under the x64 and x86 folder to your project.
In the old .csproj project, that .target file imported by following code after install the nuget packages, you can check it in your project file .csproj:
<Import Project="..\packages\CefSharp.Common.63.0.3\build\CefSharp.Common.targets" Condition="Exists('..\packages\CefSharp.Common.63.0.3\build\CefSharp.Common.targets')" />
Those files under the x86 and x64 folder would be imported when the project is running.
When you use the new .csproj project, the .target file imported by the file project.assets.json, all the files will be imported to the project when you save the .target in the project.assets.json.
That is the reason why you got those tons of dll files after install the package package CefSharp.Common. So, this is not a issue, but because they import .targets in different ways.
If you do not want show those dll files in your project, you can return back the packages.config.
Hope this helps.

Nuget with Build configurations

I'm moving over a project to make it into a nuget package. The project has preprocessor directives in it to check which custom build configuration the developer is in. If they are in Build config A then it pulls A service settings, if they are in B, then it pulls B's settings. The problem is when I package this service up and the nuget package is being used in a separate process with the same build configuration it doesn't respect the devs build configuration choice because the nuget has been compiled with whatever setting it was built in. We have set it up into 3 dlls in a single nuget package.
Is there a way to choose which nuget dll it uses based on the custom build configuration without modifying the csproj code?
Is there a way to choose which nuget dll it uses based on the custom build configuration without modifying the csproj code?
This is not supported as far as I am aware with the NuGet. You can only have one NuGet package with a specific build configurations in a single project's file. Moreover, NuGet now only supports multiple .NET framework versions, not supported multiple configurations.
You can have different NuGet packages if you have different build configurations. This project is specific use by library authors who have platform specific projects that need different NuGet packages.
Besides, It may be simpler to not use NuGet to add the assemblies to your project. Just use NuGet to pack the package with multiple dlls file, then directly reference the assemblies you need with conditions.

Deploy Web Service to Nuget Package

I have several WCF and WebAPI services as well as MVC websites in a visual studio solution. Currently, we are creating WebDeploy packages for these services and websites to deploy to IIS. I'm starting to look into Octopus Deploy for deploying our services and websites instead of WebDeploy. However, Octopus Deploy uses Nuget packages to deploy.
I'm trying to figure out how I can easily create a Nuget package that contains all the files that would normally be published into a WebDeploy package. This may not be all files in the project directory or the bin directory. I found this blog post describing how to package a csproj into a Nuget package during the build, but I found that the resulting package didn't contain any of my dependency dll's. I realize I could write a nuspec for each of these projects manually and include exactly the files I want, but I'm looking for a more automatic way as this would create more maintenance when my project changes.
Does anyone out there know a good way to generate a nuspec or Nuget package that contains only the files needed to run the application, similar to the way publishing to a WebDeploy package only includes the files it needs?
Octopus Deploy has a CLI called "Octo.exe" that can package up your application into a NUPKG.
You will need to install Octopus Tools which you can download from https://octopus.com/downloads
Please see http://docs.octopusdeploy.com/display/OD/Using+Octo.exe for the documentation and how to use it.
A good example to use Octo.exe is part of a Continuous Integration pipeline when the build has successfully passed you call it to package the application and send it to the Octopus server.
After some playing around with Visual Studio, MSBuild, and TeamCity, I discovered a method that works for me. My issues was that I did not want to package up all the files in my project directory, only those that are necessary to run the application. WebDeploy handles this quite nicely as one of the options when publishing. I already have settings in my csproj file that will create a WebDeploy package on build, but this is a zip file and I don't want the zip file in my Nuget package.
I found 2 ways to deal with this:
In TeamCity, I set up a new Build Configuration that will package any nuspec files I have and publish the resulting Nuget packages to my Octopus Deploy Nuget feed. I figured out that I can use the existing WebDeploy package that gets created by my CI build configuration as an artifact dependency and TeamCity can actually unpack the zip file when grabbing the artifacts as part of that dependency. Then my nuspec file references the entire folder structure that was extracted from the zip file and packages it into a Nupak.
I was able to modify my csproj settings to use a specific publish profile I generated in Visual Studio that would perform a WebDeploy package to file system. This would result in the same folder structure as is in the zip file from #1, but simply copied to a directory. Then my Nuget build configuration could simply grab those dependencies and package them the same way as in #1.
I decided to go with option #1 as it would require minimal changes to my existing csproj and CI build configuration, and it would not break our current method of deploying using WebDeploy.

Categories

Resources