NuGet Msbuild Pack with non-SDK project - c#

I have an "old style" .NET framework project which includes nuget references and other project references. Now I switched to the PackageReference format (removed the packages.config). I want to create a NuGet package for my project. So I added a reference to the "NuGet.Build.Tasks.Pack" package and used the MSBUILD pack target. In the first place it looked everything as expected, the resulting package contains all my references and the corresponding NuGet references. Now I have the problem, that I use also a project to project reference:
<ProjectReference Include="..\Wrapper\MyWrapper\MyWrapper.csproj">
<Project>{6b9a7dd0-b93f-3a5e-8fdf-99d0bf811652}</Project>
<Name>MyWrapper</Name>
</ProjectReference>
Based on the nuget documentation - for this reference:
Project to project references are considered by default as nuget
package references
But I want that this project reference is packaged into my package instead of a "nuget package reference". I found postings that using
PrivateAssets="all"
for the project reference could fix the problem, but adding this attribute to the project reference node does not change anything. Any help would be great!

I think you have missed something. It is not enough that you set PrivateAssets="all" for the ProjectReference. And actually, nuget will not view the referenced project as a nuget dependency and also nuget will not pack its assembly dll into the nupkg. You need other nodes.
Try these guidances:
Assume all your lib projects are target to net framework 4.7.2.
1) add the PrivateAssets="all" on the xxx.csproj file of the main project.
<ProjectReference Include="..\Wrapper\MyWrapper\MyWrapper.csproj">
<Project>{6b9a7dd0-b93f-3a5e-8fdf-99d0bf811652}</Project>
<Name>MyWrapper</Name>
<PrivateAssets>All</PrivateAssets>
</ProjectReference>
2) also add these node on the xxx.csproj file of the main project to pack the assembly dll into the nupkg:
<PropertyGroup>
<TargetsForTfmSpecificBuildOutput>$(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage</TargetsForTfmSpecificBuildOutput>
</PropertyGroup>
<Target Name="CopyProjectReferencesToPackage" DependsOnTargets="ResolveReferences">
<ItemGroup>
<BuildOutputInPackage Include="#(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference'))" />
</ItemGroup>
</Target>
3) then use this command to pack the project:
msbuild -t:rebuild,pack -p:PackageOutputPath=xxx\xxx -p:Authors="xxx" -p:Version="x.x.x"
Note: In my side, the main project called Mod and it references a project called Mod1. When I finish the pack process, you can see these in the nupkg.
It packs the refeneced dll as a lib rather than a nuget package.

Related

DinkToPdf dll not found libwkhtmltox

I am developing a .net5.0 web api and i am getting the following error while using DinkToPdf:
DllNotFoundException: Unable to load DLL 'libwkhtmltox' or one of its dependencies: The specified module could not be found. (0x8007007E)
I have followed this tutorial, with a few exceptions:
added the service added the service, which was not done in the tutorial
services.AddSingleton(typeof(IConverter),
new SynchronizedConverter(new PdfTools()));
...
services.AddScoped<IPdfService, PdfService>();
named the services differently, but that shouldn't matter
installed it via NuGet instead of Install-Package DinkToPdf
my project is just an API, frontend is not in C#, shouln't matter sincer the error is here:
return this._converter.Convert(htmlToPdfDocument);
Did everything else like in the tutorial.
For me adding this into the csproj file resolved the issue -
<ItemGroup>
<None Remove="libwkhtmltox.dll" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="libwkhtmltox.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
What is happening there is you are missing the dlls under your project directory.
you can get them here DinkToPdf dlls and include them in your project.
You can run below and it will install dlls into bin. Make sure copy those dlls into root directory
Install-Package DinkToPdfCopyDependencies -Version 1.0.8
You can also try using this package to include the dependencies:
https://www.nuget.org/packages/DinkToPdfCopyDependencies

NuGet Versioning with ProjectReference Dependencies

I have a solution containing several projects. Let's say PackageA and PackageB, where PackageB depends on PackageA with a ProjectReference.
Each project is set to also output a NuGet package on build. This process itself works perfectly but I am unable to specify a package version-range for individual builds.
E.g. I'd like to restrict PackageB to only refer to PackageA version 1.0.* (patch steps).
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup
<TargetFrameworks>netstandard2.0;netcoreapp2.0;net46</TargetFrameworks>
<RootNamespace>PackageB</RootNamespace>
<Company>MyCompany</Company>
<Authors>John Doe</Authors>
<Description>This package depends on a specific version of PackageA.</Description>
<Version>1.1.0</Version>
<Copyright>Copyright © 2018 John Doe</Copyright>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\PackageA\PackageA.csproj" />
</ItemGroup>
</Project>
MSBuild seems to ignore any Version="1.0.*" or AllowVersion="1.0.*" arguments within the ProjectReference tag.
Is there a possibility to specify a version range without breaking the ProjectReference or using PackageReference?
Short Answer
No, there is no way to limit a project reference by a version attribute of that project.
Longer Answer
If you want your dependent package to vary independently from its dependency and limit the range of changes it will depend upon, you are very much in need of using a package reference rather than a project reference (yes, even if those projects are in the same solution).
Project Reference Now
When you reference a project, you're making a declaration to your IDE that you want to include the referenced projects design time state in your dependent projects design time state so that you can use it and see changes to it in your IDE before it's built. When your dependent project is built, its dependency is built too. So, A project reference is always a latest-version reference. You cannot reference a previous version of a project, but you can reference the versioned result of a project that was built previously.
Packing a Project Reference
In line with project references being built when the dependent project is built, when you pack a project with a dependency upon another project using a project reference, dotnet pack and nuget pack assume that you're going to also be packing each of those projects as packages as well, and writes the project reference as a package dependency at the same version of the dependent project package. So, if you pack projB # v1.2.3 the package will have a dependency reference to projA # v1.2.3. If you don't pack projA # v1.2.3 or you don't publish that package (because maybe there weren't any changes to it), consumers of projB # v1.2.3 will fail the install because nuget won't find projA # v1.2.3. If you're going to insist on using project references for packages, those referenced projects should also be packages that are versioned with their host (whether they change or not).
A minor exception to the above reference rule
The exception to project references listed as package dependencies of the same version as the host is a project reference that has its assets marked as private. In those situations you either need to create a build target that will include those assets in the package or have some other convention in place to deliver the dependency to the runtime. Using the private assets route does not allow you to do what you're asking, but it is an exception to the rule of project reference becoming a LISTED dependency of your package.
Existing NuGet targets don't support this directly. A couple of issues on GitHub (1, 2) requesting this functionality have been open for years. However, with a bit of MSBuild item trickery, I was able to 'extend' ProjectReference with two attributes, PackageVersion and ExactVersion:
<!-- MyProject.csproj -->
<Project Sdk="Microsoft.NET.Sdk" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
...
<ItemGroup>
<ProjectReference Include="..\MyProject1\MyProject1.csproj" PackageVersion="[1.1.0, 2.0.0)" />
<ProjectReference Include="..\MyProject2\MyProject2.csproj" ExactVersion="true" />
<ProjectReference Include="..\MyProject3\MyProject3.csproj" />
</ItemGroup>
...
<Target Name="UseExplicitPackageVersions" BeforeTargets="GenerateNuspec">
<ItemGroup>
<_ProjectReferenceWithExplicitPackageVersion Include="#(ProjectReference->'%(FullPath)')"
Condition="'%(ProjectReference.PackageVersion)' != ''" />
<_ProjectReferenceWithExactPackageVersion Include="#(ProjectReference->'%(FullPath)')"
Condition="'%(ProjectReference.ExactVersion)' == 'true'" />
<_ProjectReferenceWithReassignedVersion Include="#(_ProjectReferencesWithVersions)"
Condition="'%(Identity)' != '' And '#(_ProjectReferencesWithVersions)' == '#(_ProjectReferenceWithExplicitPackageVersion)'">
<ProjectVersion>#(_ProjectReferenceWithExplicitPackageVersion->'%(PackageVersion)')</ProjectVersion>
</_ProjectReferenceWithReassignedVersion>
<_ProjectReferenceWithReassignedVersion Include="#(_ProjectReferencesWithVersions)"
Condition="'%(Identity)' != '' And '#(_ProjectReferencesWithVersions)' == '#(_ProjectReferenceWithExactPackageVersion)'">
<ProjectVersion>[#(_ProjectReferencesWithVersions->'%(ProjectVersion)')]</ProjectVersion>
</_ProjectReferenceWithReassignedVersion>
<_ProjectReferencesWithVersions Remove="#(_ProjectReferenceWithReassignedVersion)" />
<_ProjectReferencesWithVersions Include="#(_ProjectReferenceWithReassignedVersion)" />
</ItemGroup>
</Target>
...
</Project>
Given package versions specified in other projects like this
<!-- ..\MyProject1\MyProject1.csproj -->
<!-- ..\MyProject2\MyProject2.csproj -->
<!-- ..\MyProject3\MyProject3.csproj -->
<Project Sdk="Microsoft.NET.Sdk" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Version>1.1.3</Version>
</PropertyGroup>
...
</Project>
the generated MyProject.nuspec file will contain the following dependencies:
<?xml version="1.0" encoding="utf-8" ?>
<package>
<metadata>
<dependencies>
<group targetFramework="...">
<dependency id="MyProject1" version="[1.1.0, 2.0.0)" />
<dependency id="MyProject2" version="[1.1.3]" />
<dependency id="MyProject3" version="1.1.3" />
</group>
</dependencies>
</metadata>
</package>
This useful target can be put into Directory.Build.targets to cover all projects in your solution.
As far as i know it's not possible with ProjectReference, however there are some open issues in this topic on Github, so it might happen that they will implement it sometime.
But for now this functionality is only enabled on PackageReference. Docs.
Well let's think that through shall we? The project may have a version number embedded in in it somewhere, but it's likely to be the latest or previous version, which might not even build, and there's no guarantee that a subsequent build step won't update that value. The point at which a build system produces a versioned artifact is near the end of the build, usually the last step, which is normally the packaging or publishing step.
If your project must limit version ranges for any of its dependencies, it should take dependencies on other packages, not the projects that build them. This provides a natural asynchronous set of workflows to feed into a single product.
If you want the convenience of having dependencies built to their latest, then you must keep all the projects in sync with each other wrt compatibility. Project dependencies really only make sense for developer builds, not CI builds.
One thing you should never do, is produce two different packages with the same version numbers. Visual Studio projects are broken by design in the area of versioning, as they default to using a static version string that must be set prior to the build. If you happen to forget to bump that number, you will violate this semantic versioning rule.
Even if the Nuget/VS devs give you what you are asking for, it's not a good solution. What if the the currently checked out project is for a version outside of the specified range? Assuming the devs can figure out what code to check-out of revision control, is that really what you want to happen on your dev box? Any solution they come up with will be complex and prone to errors. Even if you've got the version checked-out, Nuget can't know you didn't make a breaking change to it.
It's better to run independent pipelines of code, review, build, package, test and publish, using only published packages as dependencies.
Are you basing your question on how NodeJS versioning works (^ and ~)? In .NET that's not possible, and not necessary.
NodeJS needs this because, you know, it's javascript. Since javascript doesn't have strict type-checking, you need some way of verifying whether packages are compatible with each other. Some properties, methods might or might not exist on certain objects. So the only way the build system (node) can verify this is through the package version selectors.
As I said, in .NET we don't need this, because it's a strict programming language. If a field, property or method doesn't exist on a class, the project simply won't build.

Multi targetting net461 and netstandard - netstandard dependencies required even in net461 consumer

I'm working on a class library that I've multi-targetted to both net461 and netstandard2.0
One of the dependencies of this class library is Microsoft.ApplicationInsights
When it was targeting just net461, I could add a reference to Microsoft.ApplicationInsights (v2.4.0) via package manager console, or nuget ui, and it would add itself as a dependency.
Once I've multi-targetted the csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net461;netstandard2.0</TargetFrameworks>
</PropertyGroup>
</Project>
... if I try to add a reference, it asks me to accept license agreements for many, many dependencies.
Of course, I duly did so.
My issue comes when I package this class library as a nuget package.
Even if my consuming application targets net461, when I install this package, I am prompted to install all the netstandard dependencies - even if my consuming application doesn't target netstandard.
Is there a way to stop my net461 targetted package requiring all the dependencies for netstandard?
Have you tried using conditions in the project file to make some dependencies target framework specific? I've had similar sounding problems, though not with creating nuget packages, and this helped.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net461;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net461' ">
<Reference Include="DependencyA" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="DependencyB" Version="1.0.0" />
</ItemGroup>
</Project>
Another idea would be to look at existing open source projects out there and see how they're solving it. Though finding one using Microsoft.ApplicationInsights may be trickier.

The type 'MySqlConnection' exists in both 'MySql.Data Issue

I have Referenced MySql.Data on one project and Other project referenced nuget package which also referenced MySqlConnector inside of it. projects has dependency .
when i compile application im getting this error
This is application hierarchy
is there any way to avoid this? or did i do anything wrong when referencing packages?
Thanks
UPDATE
this is the same namespaces from difference libs
UPDATE 2
This is the sample repo which reproduced same issue
In NET.Framework projects you can go to the reference properties and set an alias for assembly. Net core projects doesn't fully support yet aliases for assemblies. But there is a workaround to use aliases in .net core. Edit your csproj file like this:
<Project Sdk="Microsoft.NET.Sdk.Web">
...
<Target Name="ChangeAliasesOfStrongNameAssemblies" BeforeTargets="FindReferenceAssembliesForReferences;ResolveReferences">
<ItemGroup>
<ReferencePath Condition="'%(FileName)' == 'MySqlConnector'">
<Aliases>MySqlConnectorAlias</Aliases>
</ReferencePath>
</ItemGroup>
</Target>
...
</Project>
then in your cs file before all usings:
extern alias MySqlConnectorAlias;
then you can reference to you type from MySqlConnector like this:
MySqlConnectorAlias::MySql.Data.MySqlClient.MySqlConnection
It will work If you remove mysql.data reference from Your project/references.
Hope it will work for you. for me it was worked. My project is ASP.NET Core Framework. Created project in VS2017 and opening in VS2019 at that time it introduced.

How do you multi-target a .NET Core class library with csproj?

When .NET Core still used the project.json format, you could build a class library targeting multiple frameworks (e.g. net451, netcoreapp1.0).
Now that the official project format is csproj using MSBuild, how do you specify multiple frameworks to target? I am trying to look for this from the project settings in VS2017, but I am able to only target a single framework from the .NET Core frameworks (it doesn't even list the other full .NET Framework versions which I do have installed):
You need to manually edit the project file and add s to the default TargetFramework and basically change it to TargetFrameworks. Then you mention the Moniker with a ; separator.
Also you can put the Nuget package references in a conditional ItemGroup manually or using VS Nuget Package Manager.
Here is what your .csproj should look like:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard1.6;net452</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net452'">
<PackageReference Include="Microsoft.Azure.DocumentDB">
<Version>1.12.0</Version>
</PackageReference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.6'">
<PackageReference Include="Microsoft.Azure.DocumentDB.Core">
<Version>1.1.0</Version>
</PackageReference>
</ItemGroup>
</Project>
Another workaround I do these days because of missing documentation is that I create a project in VS2015 and form the project.json using the available documentation and intellisense, then open the solution in VS2017 and use the built-in upgrade. I will then look at the csproj file to figure out how to make that configuration happen.
Multi-targeting more esoteric targets without a Moniker:
Microsoft:
PCLs are not recommended+
Although PCLs are supported, package authors should support
netstandard instead. The .NET Platform Standard is an evolution of
PCLs and represents binary portability across platforms using a single
moniker that isn't tied to a static like like portable-a+b+c monikers.
If you want to target a Portable Profile it doesn't have a predefined moniker so Portable Profiles also can't infer TargetFrameworkIdentifier, TargetFrameworkVersion, and TargetFrameworkProfile. Also a compiler constant isn't defined automatically. Finally you have to add all assembly references none are provided by default.
This Example below is taken from a project that used the dynamic keyword so it additionally needed the Microsoft.CSharp assembly, thus you can see how it's references for different targets.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard1.5;net40;portable40-net45+sl5+win8+wp8</TargetFrameworks>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)'=='portable40-net45+sl5+win8+wp8'">
<TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Profile158</TargetFrameworkProfile>
<DefineConstants>$(DefineConstants);PORTABLE158</DefineConstants>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='netstandard1.5'">
<PackageReference Include="Microsoft.CSharp" Version="4.3.0" />
<PackageReference Include="System.ComponentModel" Version="4.3.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net40'">
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='portable40-net45+sl5+win8+wp8'">
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Windows" />
</ItemGroup>
</Project>
You can manually edit .csproj file for this and set TargetFrameworks (not TargetFramework) property.
<TargetFrameworks>net451;netstandard1.4</TargetFrameworks>
For example see EFCore.csproj:
https://github.com/aspnet/EntityFrameworkCore/blob/951e4826a38ad5499b9b3ec6645e47c825fa842a/src/EFCore/EFCore.csproj
I actually selected Class Library (.NET Core).
That is not the project template you want if your library needs to work on multiple platform targets. With this project template, your library can only ever be used in a project that targets .NETCore. The PCL library approach was retired, you now have to pick a .NETStandard.
You do so by starting the project with the "Class Library (.NET Standard)" project template. You now have the option of picking the .NETStandard version. The current compatibility grid is here.
Hopefully they'll keep that linked article updated. This is in flux, .NETStandard 2.0 was nailed down but does not ship yet. Targeted for Q2 of 2017, end of spring probably, it currently shows as 97% done. I overheard the designers saying that using 1.5 or 1.6 is not recommended, not compatible enough with 2.0
I did a simple guide to multi-targeting net framework and netcore which starts with the minimum 15 second fix but then walks you through each of the complications.
The very simplest approach is:
First, get a netcore or netstandard target working.
Then
Edit the .csproj project file and work through these steps for the other targets.
Change the <TargetFramework> tag to <TargetFrameworks> and add your next target to the list, delimited by ;
Learn about conditional sections in your csproj file. Create one for each target. Use them to declare dependencies for each target.
Add <Reference />s for System.* dlls for any netframework targets just by reading what the build error messages say is missing.
Deal with NuGet <PackageReference />s dependencies in the cases where they are not the same for each target. (The easiest trick here is to temporarily revert to single targetting so that the GUI will just handle the Nuget references correctly for you).
If you must: learn a creative variety of techniques, workarounds and timesavers to deal with code that doesn’t compile on all targets.
Know when to cut your losses when the cost of adding more targets is too high.

Categories

Resources