Include flat file in NuGet package and deploy into target solution - c#

Apologies in advance, this is relatively new to me and has been asked in various ways several times...
I've been trying unsuccessfully to do the following:
Create a NuGet package of my common code (can do this) which
includes a specflow.json file - we'll call this common code NuGet
package Base.nupkg.
Reference Base.nupkg in target solution (can do this) and for
specflow.json file to be copied to the target solution and visible
in target solution for modification in target solution - we'll call
this solution Target.sln.
The problem is, the specflow.json file is not being deployed/included in the Target.sln when Target.sln references Base.nupkg.
I have tried a number of things such as:
<ItemGroup>
<None Include="specflow.json" PackagePath="Resources" Pack="true" />
</ItemGroup>
And:
<ItemGroup>
<Content Include="specflow.json">
<CopyToOutputDirectory>PreserveNewest
</CopyToOutputDirectory>
</Content>
</ItemGroup>
And:
<ItemGroup>
<AdditionalFiles Include="specflow.json">
<CopyToOutputDirectory>PreserveNewest
</CopyToOutputDirectory>
</AdditionalFiles>
</ItemGroup>
And:
<ItemGroup>
<Content Include="specflow.json">
<Pack>true
</Pack>
<CopyToOutputDirectory>PreserveNewest
</CopyToOutputDirectory>
<ContentTargetFolders>Resources\
</ContentTargetFolders>
</Content>
</ItemGroup>
And:
<ItemGroup>
<Content Include="$(MSBuildThisFileDirectory)specflow.json">
<Pack>true
</Pack>
<Link>specflow.json
</Link>
<CopyToOutputDirectory>PreserveNewest
</CopyToOutputDirectory>
</Content>
</ItemGroup>
I've tried following the Microsoft instructions here but no luck. I've also looked at various Stackoverflow questions such as:
Set content files to "copy local : always" in a nuget package
Specifying files to add to a nuget package in .csproj file
.targets file within nuget package - how to include content files into a build
The Base.nupkg is an older test unit project and has migrated from packages.config to package references. Same goes for Target.sln. Both target .Net 4.7.2.
Background as to why I want to do this is, Specflow have recently announced they are retiring Specflow+Runner. My organisations automation estate uses the html report from Specflow+Runner. Anyway, I migrated to SpecFlow.MSTest and still want an html report. So, I am also using SpecFlow LivingDoc - this requires the specflow.json file. Thus, when colleagues make use of the Base.nupkg, I would rather them not have to also manually add the specflow.json file to their target solutions, I was hoping to be able to reduce any manual steps and automatically do this when they reference Base.nupkg.
If anyone has a simple solution which consistently works, please let me know.
Thanks.

Related

How to control output of a nuget package dependencies during build

I would like to support backward compatibility in my application.
Simply saying - one app needs to work using different versions of a dll depending on a flag which the app get's during runtime.
I've simplified everything and created a test solution with 2 projects in it.
Each project has it's own version of the same nuget package.
I picked System.Drawing.Common cause it has no dependencies.
ClassLibrary1 contains System.Drawing.Common of version 4.5.0.
ClassLibrary2 contains System.Drawing.Common of version 6.0.0.
Both projects have same output path:
<OutputPath>..\DEBUG\</OutputPath>
When I build my solution I get just one System.Drawing.Common.dll in my output folder:
Cause both dlls have one name and only version is different.
The desired behavior on the pictures below:
Distribute the nuget package dependencies into different folders according to versions.
Add suffix to the nuget package dependencies according to versions.
The idea is in controlling output of the nuget package dependencies.
Do you have any idea how I can achieve that ?
P.S. all other logic - resolving dependencies according versions etc is out of scope of this question.
It's possible.
First you need to add GeneratePathProperty to PackageReference element in csproj file
<ItemGroup>
<PackageReference Include="System.Drawing.Common">
<Version>4.5.0</Version>
<GeneratePathProperty>true</GeneratePathProperty>
</PackageReference>
</ItemGroup>
It allows us using $(PkgSystem_Drawing_Common) variable which contains a path to the nuget package.
Then we need to create a msbuild targets file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CopyNugetDll" BeforeTargets="BeforeCompile" Outputs="System.Drawing.Common.dll">
<XmlPeek XmlInputPath="$(ProjectPath)" Query="Project/ItemGroup/PackageReference[#Include='System.Drawing.Common']/Version/text()">
<Output TaskParameter="Result" PropertyName="NugetPackageVersion" />
</XmlPeek>
<ItemGroup>
<NugetrDll Include="$(PkgSystem_Drawing_Common)\lib\net461\System.Drawing.Common.dll" />
</ItemGroup>
<Message Text="Copying #(NugetrDll) to $(OutDir)" Importance="high" />
<Exec Command="copy $(PkgSystem_Drawing_Common)\lib\net461\System.Drawing.Common.dll $(OutDir)\System.Drawing.Common.$(NugetPackageVersion).dll" />
</Target>
</Project>
Here using xpath we select version from project.assets.json file and save it in NugetPackageVersion variable. Exec copy is used to copy the dll to a specific location with a specific prefix which contains a value from NugetPackageVersion variable.
Lastly you need to include msbuild targets file to a project
<Import Project="CopyDll.targets" />
This just isn't how package resolution works in .NET, you get one version of each package which is decided at restore time.
There may be some funky options if you have a very niche problem, but it sounds like maybe you're trying to solve a common problem in an uncommon way which is generally a bad idea.
Typically for the problem of backwards compatibility the onus is on the publisher of the library rather than the consumer of the library to make sure it all works by not making breaking API changes.

Can't debug .NET Core: Could not load file or assembly 'System.Runtime, Version=4.2.1.0 / 4.2.0.0

This is not a question. Just wanted to share how I managed to finally debug .net core projects in Visual Studio after having the error in the title.
I tried many many suggestions, but each time I tried to debug a .net core project - even a completely new Azure function of HTTP trigger template (V2) - I got the error that System.Runtime Version=4.2.1.0 is missing.
First, I noticed that the new project was targeting .net standard. I changed it to .net core, so my .csproj file looked like that:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<AzureFunctionsVersion>v2</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.13" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>
I tried adding
<PropertyGroup>
<UseNETCoreGenerator>true</UseNETCoreGenerator>
</PropertyGroup>
and
<PackageReference Include="System.Runtime" Version="4.3.1" />
to the .csproj file but that didn't help either.
I even tried to uninstall VS 2017 and VS 2019 and all .net core packages, and re-install them. But still no luck.
Then I came to a conclusion that is has to do with my machine - some data has to be corrupted.
Microsoft store data for .net core on the user's "hidden" %APPDATA% folder:
C:\Users\<USERNAME>\AppData\Local\AzureFunctionsTools\
Apparently, mine was missing quite a lot of data. About 300 MB instead of ~700. I guess that the slow internet connection I got in our offices has to do with it.
I found this article:
https://github.com/Azure/azure-functions-host/issues/3759
soninaren, mentions the steps he did, and also provides a source for undamaged AzureFunctionsTools templates:
https://github.com/soninaren/Workarounds/releases/download/1.0.0/AzureFunctionsTools.zip
Just unzip, Open each manifest.json file you find in there and replace the username in the tag TemplatesDirectory so it will point to your username folder. Then, delete your AzureFunctionsTools folder (C:\Users\<USERNAME>\AppData\Local\AzureFunctionsTools\) and copy the edited zip content instead.
Voila, you should be able to debug .net core projects and your new Azure function projects will initially target .net core.
Hope this helps,
Ron
Thanks Ron for his contribution. In order to let others find a solution quickly in SO when encountering related problems, I write here Ron's efforts:
If you face this problem,
1, First, Show hidden folders on your computer. The Azure Function Tools is in this directory: C:\Users\<USERNAME>\AppData\Local\AzureFunctionsTools\, delete the azure function tools folder.
2, Second, click this link to download Azure Function Tools.
3, Third, unzip, then open each manifest.json file. Replace the username in the tag TemplatesDirectory. After that, copy them to the C:\Users\<USERNAME>\AppData\Local\AzureFunctionsTools

Nuget Library - Copy DLL of Library to current project's output directory

So to best explain what I would like to do:
If you install the nuget package NUnitTestAdapter to your project, when building your project, you will have a NUnit3.TestAdapter.dll in your project's output directory.
I would like to do the same. I have a library that I'm packaging up, but when I install it to another project and build it, my dll isn't included like NUnit's is.
As for why I need to do this, I'm writing a test reporter, which produces JSONs, XMLs, HTML etc reports for all tests run.
I'm having this run in the AppDomain.CurrentDomain.ProcessExit event, however this is limited to around 2 seconds, so if my reports aren't generated in 2 seconds, it won't work. So instead, on processexit, it'll execute my report DLL which won't have a time restraint on it.
Thanks!
Nuget Library - Copy DLL of Library to current project's output directory
When you download the package NUnit3TestAdapter and open it with NuGet Package explorer(Get it from Microsoft Store), you will find following content:
There is a NUnit3TestAdapter.props with property CopyToOutputDirectory in the build folder:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Content Include="$(MSBuildThisFileDirectory)NUnit3.TestAdapter.dll">
<Link>NUnit3.TestAdapter.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>False</Visible>
</Content>
<Content Include="$(MSBuildThisFileDirectory)NUnit3.TestAdapter.pdb" Condition="Exists('$(MSBuildThisFileDirectory)NUnit3.TestAdapter.pdb')">
<Link>NUnit3.TestAdapter.pdb</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>False</Visible>
</Content>
<Content Include="$(MSBuildThisFileDirectory)nunit.engine.dll">
<Link>nunit.engine.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>False</Visible>
</Content>
<Content Include="$(MSBuildThisFileDirectory)nunit.engine.api.dll">
<Link>nunit.engine.api.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>False</Visible>
</Content>
</ItemGroup>
</Project>
So, when we install this package to the project, this file NUnit3TestAdapter.props will imported to the project file, then the dll files will be copied to the output folder.
If you want that, you can also use this method.
Hope this helps.
So with the help of Leo Liu-MSFT, I've managed this.
First I had to create a props file like in Leo's answer
Then I had to create a post-build event on the project, copying the props file to my target directory.
copy /Y "$(ProjectDir)$(TargetName).props" "$(TargetDir)$(TargetName).props"
Then I created a nuspec file, which copies the props and dll from my target directory, to a build directory in the nuget package
<files>
<file src="bin\Release\**\Report.props" target="build" />
<file src="bin\Release\**\Report.dll" target="build" />
</files>
And then package up the library via nuget pack ###.nuspec
And then when importing the library through nuget, the props file would be automatically push my files through on a successful build.
I had to make sure I called the props file the same name as my project id.

Include Nuget dependencies in my build output?

I am building a modular .NET core application that can load extensions at runtime using MEF. I have 2 projects, one is a library that I want to be able to load at runtime, then I have my main application that will do the loading.
My library project has some Nuget dependencies. In order to load my library at runtime, I need those Nuget dependencies to be available next to the library at runtime, but building using VS2017 does not include these Nuget DLLs as part of the output.
How do I get Nuget DLLs included when I build my library?
Edit: I have tried dotnet publish and dotnet pack, but both of those make me a nupkg file only containing my DLL and not the nuget DLLs I need with it. Also, I can't load a nupkg file at runtime very easily, which is why I'd like to just get the resulting assemblies themselves on their own.
For what it's worth, this is what my csproj looks like:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
<AssemblyName>JSON.plugin</AssemblyName>
<IncludeBuiltProjectOutputGroup>true</IncludeBuiltProjectOutputGroup>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Composition" Version="1.0.31" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\BDDGen.Types\BDDGen.Types.csproj" />
</ItemGroup>
</Project>
In order to make the build process copy all referenced dll files from NuGet packages from the cache folder into the build output, set this property inside a <PropertyGroup>:
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

ABCpdf nuget package XULRunner folder is corrupt?

I'm trying to update my (previously working) pdf-creating web application to use the ABCpdf.NET and ABCpdf.NET Gecko Runtime nuget packages.
I've installed both packages (both are version 8.1.1.6) however when I run my application, I get the following WebSupergoo.ABCpdf8.Internal.PDFException:
Failed to add HTML: Gecko engine hit an error it was unable to recover
from. Possible causes: XULRunner folder is corrupt or is from another
version of ABCpdf.
After installing the ABCpdf.NET Gecko Runtime package, I got a dialog telling me that I would need to manually copy the XULRunner folder into my output directory. In order to achieve this, I added the following to my applications .csproj file:
<Target Name="AfterBuild">
<CallTarget Targets="CopyAbcpdfToDeployFolder" />
</Target>
<Target Name="CopyAbcpdfToDeployFolder">
<ItemGroup>
<SourceDir Include="$(ProjectDir)XULRunner\**\*.*" />
</ItemGroup>
<Copy SourceFiles="#(SourceDir)" DestinationFolder="$(WebProjectOutputDir)\$(OutputPath)%(SourceDir.RecursiveDir)\XULRunner" />
</Target>
(This seems to be working correctly - the XULRunner folder and its contents are present in my bin folder after a build)
The line of code that is failing is as follows:
theDoc.AddImageUrl(url);
Can anyone help me get this working?
As it turns out, my changes to the .csproj file we not copying all files into the correct subfolders. In order to copy the folder structure and files recursively, the XML should have looked like this:
<Target Name="AfterBuild">
<CallTarget Targets="CopyXULRunnerToDeployFolder" />
</Target>
<Target Name="CopyXULRunnerToDeployFolder">
<ItemGroup>
<MyFiles Include="XULRunner\**\*.*" />
</ItemGroup>
<Microsoft.Build.Tasks.Copy SourceFiles="#(MyFiles)" DestinationFiles="#(MyFiles->'$(OutputPath)\XULRunner\%(RecursiveDir)%(Filename)%(Extension)')"/>
</Target>
I was able to accomplish the same outcome with the following MSBuild xml:
<ItemGroup>
<Content Include="XULRunner\**\*.*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
I fell upon this setup after dealing with issues concerning the building of a package via MSDeploy not including the XULRunner files.
Not sure if there's anything patently wrong with this, but so far it works for me on a multiple staged deployment setup.

Categories

Resources