Visual Studio 2017 csproj - dotnet pack ProjectReference as exact version - c#

I am trying to get dotnet pack to generate exact version references when creating NuGet packages. Let's say I have the following class hierarchy:
api.csproj:
<ItemGroup>
<ItemGroup>
<ProjectReference Include="..\api.types\api.types.csproj" />
</ItemGroup>
</ItemGroup>
api.types.csproj has no other dependencies and is simply used for the wire objects.
I have a custom process that updates the Version in all my csproj files prior to restore and build. When I run dotnet pack I would like to be able to control the dependency in api.nupkg such that api.types is an exact version reference. Is there an out of the box way to do this?

Related

Include flat file in NuGet package and deploy into target solution

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.

How to set dependencies when I use .NET Standard 2.0 DLL libraries with a .NET Framework console application?

I can't figure out how should I set up dependencies (where to add EntityFramework nuget packages) in this scenario:
Core.Persistence project which compiles to .NET Standard 2.0 DLL library. I have Entity Framework 6, database entity classes for EF, DbContext etc. It is supposed to depend just on EntityFrameworkCore.
Core.Domain project which also compiles to .NET Standard 2.0 DLL library. I want to put my business object POCO classes here. This is supposed to have no dependencies.
Core.Application project, this is .NET Standard 2.0 DLL library. I have all application logic here. It depends on Core.Persistence because it makes database queries and Core.Domain because it produces bussiness objects from query results.
Client.ConsoleClient project. It makes .NET Framework 4.7.2 executable. It is supposed to depend only on Core.Application, but I have a problem here.
Client.WindowsClient project which I don't want to focus in this question.
So, this is what I have done:
The problem is, that I'm getting System.IO.FileLoadException when I try to call method from Core.Application.
It says that it cannot find System.Interactive.Async file (which is dependency of EntityFrameworkCore). After I add this file as dependency - there are other System.IO.FileLoadException errors.
So, temporarily I have added EF6 Core NuGet package to my Client.ConsoleClient, and problems with System.IO.FileLoadException are gone, but I feel I'm doing something wrong.
At this moment I figured out, that Visual Studio is not copying DLL files from Core.xxx projects outputs into Client.ConsoleClient project output, and that's why I'm getting errors.
How to fix this properly?
This is a wellknown and quite old hurt logged on GitHub at:
dependencies don't flow from new NET Standard project to old desktop projects through project references link
A possible solution is to add the NuGet dependency to the Full NET Framework project, as you did.
The other suggestion to include the following to the .csproj project file of the Full NET Framework project is also working for me.
<PropertyGroup>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
Note that I am using package references in the NET Standard projects.
As for now, it looks like NET Standard projects are best to be consumed as NuGet packages, as these would include any dependent references as NuGet packages into the target project.
Core.Persistence.csproj referencing Entity Framework
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.6" />
</ItemGroup>
</Project>
Core.Application.csproj referencing Core.Persistence
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Core.Persistence\Core.Persistence.csproj" />
</ItemGroup>
</Project>
ConsoleClient.csproj referencing Core.Application
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<!-- ... -->
</PropertyGroup>
<PropertyGroup>
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>
<!-- ... --->
<ItemGroup>
<ProjectReference Include="..\Core.Application\Core.Application.csproj">
<Project>{067b3201-3f65-4654-a0fb-e8fae521bf29}</Project>
<Name>Core.Application</Name>
</ProjectReference>
</ItemGroup>
</Project>
The new SDK format csproj files don't play terribly well with the legacy format project files.
But fear not as .NET Framework console apps can use the SDK format!
Make sure you have your work committed to source control, or make a copy of the folder, and then do the following:
Delete Properties\AssemblyInfo.cs from Client.ConsoleClient. We won't be needing this any more as the contents of that file now go into the project file.
Delete packages.config - again, Nuget references will be stored in the project file - that's if you need any Nuget references after we reference Core.Application later.
Open Client.ConsoleClient.csproj in a text editor and change the contents to:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net472</TargetFramework>
</PropertyGroup>
</Project>
Reload the project in Visual Studio.
Add a reference to Core.Application and add any Nuget packages you need.
If you had any content in Properties\AssemblyInfo.cs other than versions at 1.0.0.0, right click the project in Solution Explorer and click Package. Add the details you need and then save:
That's it, although there are 2 others things you might need to do depending on your circumstances:
If there are files which should be excluded, you'll need to exclude them, as the new project format includes all relevant file types by default.
You might have to set the language version. In my Visual Studio 2019 Preview, latest (latest minor version of C#) is the default so I don't need to do this.

Getting "System.Data.SqlClient is not supported on this platform" when launched as dotnet cli tool

We have a simple netcore 2.2 console application using DbContext from Microsoft.EntityFrameworkCore. When launched from console as is it works as expected.
However we decided to utilize it as a dotnet CLI tool. It's .csproj file contains:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AssemblyName>dotnet-dbupdate</AssemblyName>
<Title>Db Updater</Title>
<Version>1.0.1</Version>
<PackageId>DbUpdater</PackageId>
<Product>DbUpdater</Product>
<PackageVersion>1.0.1</PackageVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.0" />
</ItemGroup>
</Project>
We pack it to our Nuget server with dotnet pack. Then in a target folder we've got the following .csproj file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>
<ItemGroup>
<DotNetCliToolReference Include="DbUpdater" Version="1.0.1" />
</ItemGroup>
</Project>
From this folder we restore it and exec:
dotnet restore
dotnet dbupdate
And suddenly, on DbSet's ToList method invocation we receive:
System.Data.SqlClient is not supported on this platform
Definetely there is an issue with launching it as a dotnet CLI tool. However yet we failed to get what this issue is and how to solve it. Searching on the web did not give us any ideas what to try.
Try to specify the .NET version to use for CLI:
dotnet dbupdate --fx-version 2.2.4
If the above does not work, also try with the other version you have installed (2.2.2).
In essence the version of .NET used to run from CLI, the target SDK of the console app and the package versions of the dependencies all have to match for incompatibility issues to be avoided.
Just added compatibility v2 to local.settings.json:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"FUNCTIONS_V2_COMPATIBILITY_MODE": "true"
}
}
I have come across the same issue, this is happening because of the wrong version of System.Data.SqlClient is used, in my case application is built with .NET 4.6 and the class library in .Net Standard 2.0 which has a dependency on System.Data.SqlClient.
The issue is resolved after replacing the appropriate version of System.Data.SqlClient(.NET 4.6 in my case) in the production environment.
If you want to run it on Linux OS just make sure to publish your solution using the correct Target Runtime. For example pick linux-x64 if you want to run it on Red Hat Enterprise Linux.
Note that the ToList() method fires the SQL command, say, the first time which he uses the corresponding DLL. So, simply your error says that There's a dependency mismatch for Microsoft.EntityFrameworkCore.SqlServer or System.Data.SqlClient, you know that the second one is a dependency for the first one. There are some dependencies for the second one too, however I think your problem doesn't come from it.
Check out default references (versions) after packing and try to change to a suitable one. Unfortunately, We can't reproduce your problem, so try this solution and let us know the result.
Edit
According to dotnet-pack documentation :
NuGet dependencies of the packed project are added to the .nuspec
file, so they're properly resolved when the package is installed.
Project-to-project references aren't packaged inside the project.
Currently, you must have a package per project if you have
project-to-project dependencies.
Web projects aren't packable by default. To override the default
behavior, add the <IsPackable>true</IsPackable> property (inside
<PropertyGroup>) to your .csproj file.
I think you need to include the following inside your .csproj file :
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.0.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.4.0"/>
</ItemGroup>
Also, no more need to use dotnet restore based on the following from the dotnet-pack documentation :
Starting with .NET Core 2.0, you don't have to run dotnet restore
because it's run implicitly by all commands, such as dotnet build and
dotnet run, that require a restore to occur. It's still a valid
command in certain scenarios where doing an explicit restore makes
sense.
If you are developing a project with Asp.net core 2.2 to pay attention to the following issues
The compiler cannot move the dll files to the destination folder when you change the target project settings (launch settings to cli) or type (as class lib to standard lib) or deleted some dipendecies from nuget section. (Compiler bug and microsoft corrected this in vs 2019 last 2 revision) You can try to move it manually but it's not guaranteed. Downgrading maybe a resulation in this case.
Asp.net framework core compiler looks primarily at the project file and other referenced modules take less priority.
dotnet restore and dotnet update could'nt provide the settings as according our changes. For example if you remove a package and made a -dotnet restore command, after look to the nuget dependecy part of the visual studio. They maybe still there.
For this reason, you try to place the Microsoft.EntityFrameworkCore.SqlServer to the final file of the final project.
solution with above
Self Contained application.
In this case, if you are using a DLL related to another application (such as a SQLBase driver), or you can put other nuget dependencies to your application by isolating these DLLs. This gives you the flexibility to work from other resources in the system. In your case you should do this for Microsoft.EntityFrameworkCore.SqlServer
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
Please write comment if you dont agree

How can I include a NuGet package with native dlls in my new CSPROJ Class Library?

I have a class library which I just migrated to the new csproj format that has a dependency on SQLite.Core.
SQLite has native dependencies x64/SQLite.Interop.dll and x86/SQLite.Interoop.dll which used to get copied to the output folder for any project adding my package. This was taken care of by NuGet by automatically including the following import in the old csproj file:
<Import Project="..\packages\System.Data.SQLite.Core.1.0.106\build\net451\System.Data.SQLite.Core.targets" Condition="Exists('..\packages\System.Data.SQLite.Core.1.0.106\build\net451\System.Data.SQLite.Core.targets')" />
After migrating to the new csproj I can build my library as a NuGet package which correctly includes SQLite.Core as a dependency however whoever consumes my NuGet library does not get the native dependencies coppied to the output folder.
On the other hand, if the consumer first adds the SQLite.Core then add my package everything works correctly.
Any idea how I can restore the behaviour before the migration? Below is the migrated csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageId>My.Library</PackageId>
<Description>Some Library.</Description>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net452</TargetFramework>
<AssemblyName>My Library</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.106" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
</Project>
Since System.Data.SQLite.Core uses build-time logic to include the package to the content, the default dependency settings for PackageReference aren't a good fit if you build a library referencing that package. By default, PackageReference will not forward contentFiles, build assets and analyzers for transitive references.
To change that behavior, edit your PackageReference to:
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.106" PrivateAssets="none"/>
This will ensure that the package will behave exactly the same when reference directly or transitively via your library. In your specific case, PrivateAssets could also be contentFiles;analyzers since only build would need to be forwarded but since the package only contains build assets, it doesn't matter.
See Controlling dependency assets for more details.

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>

Categories

Resources