.NET Core 2.1 version error with Cake Build 4.0 NuGetRestore and MSBuild actions - powershell

Cake Build 4.0.0 runs NuGetRestore and MSBuild methods by executes MSBuild CLI command. From my understanding, Cake downloads certain version of MSBuild. In my solution, it is mostly .NET Framework, but our testing project is targeting .NET Core 2.1 (we will eventually move our whole project to .NET Core 2.1+ but cannot right now). I am experiencing the following error:
C:\git\OurProduct\PPUXL\tools\.dotnet\sdk\2.1.4\Sdks\Microsoft.NET.Sdk\build\Microsoft.NET.TargetFrameworkInference.targets(135,5): error : The current .NET SDK does not support targeting .NET Core 2.1. Either target .NET Core 2.0 or lower, or use a version of the .NET SDK that supports .NET Core 2.1. [C:\git\OurProduct\PPUXL\src\Portals\Core\OurProduct.Tests\OurProduct.Tests.csproj]
So normally I would download a new SDK, but we are going to run the script on Azure DevOps on a build agent and the SDKs are not part of our workstation but are downloaded and compiled by Cake via the Powershell script we run.
Here is the code the causes the error:
Task("Restore")
.Does(() =>
{
//We need to change this code if we switch from .NET Framework to .NET Core for this project.
NuGetRestore(
solution,
new NuGetRestoreSettings()
{
PackagesDirectory = packagesDirectory
}
);
var projects = GetFiles("./**/*.csproj");
foreach(var project in projects)
{
NuGetRestore(
project,
new NuGetRestoreSettings()
{
PackagesDirectory = packagesDirectory
}
);
}
});
Task("Build")
.Does(() =>
{
MSBuild(
SAMLProject,
new MSBuildSettings()
.SetConfiguration(configuration)
.WithProperty("DeployOnBuild", "true")
.WithProperty("PublishProfile", configuration)
.WithProperty("publishUrl", SAMLDeployDirectory)
.WithProperty("WebPublishMethod", "FileSystem")
);
var projects = GetFiles("./**/*.csproj");
foreach(var project in projects)
{
if(!project.FullPath.Contains("Tests") && !project.FullPath.Contains("SAML"))
{
MSBuild(
project,
new MSBuildSettings()
.SetConfiguration(configuration)
);
}
}
MSBuild(
testProject,
new MSBuildSettings()
.SetConfiguration(configuration)
);
});
I can get prevent the error by doing this:
Task("Restore")
.Does(() =>
{
//We need to change this code if we switch from .NET Framework to .NET Core for this project.
NuGetRestore(
solution,
new NuGetRestoreSettings()
{
PackagesDirectory = packagesDirectory
}
);
var projects = GetFiles("./**/*.csproj");
foreach(var project in projects)
{
if(!project.FullPath.Contains("Tests") && !project.FullPath.Contains("SAML"))
{
NuGetRestore(
project,
new NuGetRestoreSettings()
{
PackagesDirectory = packagesDirectory
}
);
}
}
});
Task("Build")
.Does(() =>
{
MSBuild(
SAMLProject,
new MSBuildSettings()
.SetConfiguration(configuration)
.WithProperty("DeployOnBuild", "true")
.WithProperty("PublishProfile", configuration)
.WithProperty("publishUrl", SAMLDeployDirectory)
.WithProperty("WebPublishMethod", "FileSystem")
);
var projects = GetFiles("./**/*.csproj");
foreach(var project in projects)
{
if(!project.FullPath.Contains("Tests") && !project.FullPath.Contains("SAML"))
{
MSBuild(
project,
new MSBuildSettings()
.SetConfiguration(configuration)
);
}
}
MSBuild(
testProject,
new MSBuildSettings()
.SetConfiguration(configuration)
);
});
How can run the build methods to target the correct .NET Core libraries using Cake? I want the build to all happen within my Powershell script and my Cake script with no environmental influence. Thanks in advance.

Cake doesn't download any tools automatically, it does resolve tools automatically though.
The error would suggest that the machine the build is running on lacks an .NET Core SDK that can build .NET Core 2.1 apps.
You can download an install .NET Core SDK from https://dotnet.microsoft.com/download/dotnet-core/2.1
For Azure DevOps you can use the .NET Core Tool Installer task to ensure
If you want to contain your tools with in repository and not install anything into i.e. program files, then installing SDK using a PowerShell/Bash boostrapper is a way to ensure everyone's gets and uses the same SDK without affecting the rest of the system.
Microsoft provides scripts for obtaining the SDK at
https://dot.net/v1/dotnet-install.ps1
https://dot.net/v1/dotnet-install.sh
Example usage:
dotnet-install.ps1 -Channel 'LTS' -Version '2.1.603' -InstallDir '.\dotnet';
Cake project itself uses this method in it's build.ps1, downloading the SDK version it needs if it's not available on the machine.
If you also want to ensure you're using the downloaded SDK to build your projects, then you can switch from NuGetRestore/MSBuild aliases to
DotNetCoreRestore
DotNetCoreBuild
These aliases will invoke the .NET Core CLI, and if the downloaded .NET COre CLI is first in path or specified on the .NET Core aliases settings ToolPath property, then it'll be the one used. .NET Core SDK can build both .NET Core and .NET Framework projects. I.e. the Cake project achieves this in its in it's build.ps1 by adding the dotnet folder first in path environment variable.

Related

Blazor component - Failed to fetch dynamically imported module when packed in nuget

I created a blazor component that loads an isolated js interop file (target framework .Net 7)
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var dotNetObjRef = DotNetObjectReference.Create(this);
_routeMapModule = await JsRuntime.InvokeAsync<IJSObjectReference>("import", "./_content/MyComp/MyJs.js");
await _routeMapModule.InvokeVoidAsync("CompInit", _elRef, dotNetObjRef);
}
}
MyComp is the ProjectName so the path to get the file is "./_content/MyComp/MyJs.js".
As long as I use this component as a project reference (blazor server), everything works fine.
But as soon as I package this component in a Nuget (azure pipeline), and reference it in the project (instead of a project reference), I get "Failed to load resource: the server responded with a status of 404 () / Failed to fetch dynamically imported module when packed in nuget".
When I check the nuget in my local nuget storage (unziping it), I find the js file in the root but if I search it in the main app generated bin, it is not there.
Is there a specific parameter for the Nuget deployment ?
I tried to create the nuget directly from visual studio and/or to modify the generation parameters on Azure.
The final nuget contains the js resource file but it does not seem to be published in the main project (the one that references the nuget).
Also tried to move the file referenced in wwwroot but same problem.
What's weird is that everything works fine as long as I'm in "project reference" mode but the path "./_content/MyComp/MyJs.js" doesn't seem to follow when it's packaged in a nuget.
Any idea ?
Main Blazor App: https://jmpnet.visualstudio.com/JmpNetPublic/_git/MainBlazorApp
Blazor component App: https://jmpnet.visualstudio.com/JmpNetPublic/_git/MyComp
Nuget Feed for Blazor component App:
Name: JmpNetPublic
Source: https://jmpnet.pkgs.visualstudio.com/JmpNetPublic/_packaging/JmpNetPublic/nuget/v3/index.json
Update (29.12.2022):
I have no problem to load the module as long as I stay in project reference (with or without lazy loading).
The problem happens only when the component is packaged in Nuget.
When deploying the Nuget, the js file does not follow.
It seems to be mostly a Nuget packaging issue (via Azure) but I can't find the settings that force the deployment of the js file.
OK. The problem was with the Azure Pipeline configuration.
if I generate the nuget directly on my workstation and push it, everything works fine.
But as soon as I did the generation using an Azure pipeline, the js file was no longer deployed.
I was actually using YAML Nuget commands (targeting .net framework) with a .Net Core project.
Now that I use ".Net Core" YAML , everything works correctly.
Lazy load the module:
public partial class TestComp : ComponentBase, IAsyncDisposable
{
[Inject]
private IJSRuntime JsRuntime { get; set; }
private readonly Lazy<Task<IJSObjectReference>> moduleTask;
[Parameter]
public string? Message { get; set; }
public TestComp()
{
moduleTask = new(() => JsRuntime!.InvokeAsync<IJSObjectReference>(
identifier: "import",
args: "./_content/MyComp/MyScript.js")
.AsTask());
}
private async Task Click()
{
var module = await moduleTask.Value;
Message += "...click";
await module.InvokeAsync<string>("popup", Message);
}
public async ValueTask DisposeAsync()
{
if (moduleTask.IsValueCreated)
{
var module = await moduleTask.Value;
await module.DisposeAsync();
}
}
}
Note: I am assuming MyScript.js is in the wwwroot folder of the MyComp project which is the NuGet package.

Add options when moving from NetCore 2 Newtonsoft JSON to the new JSON API in NetCore 3

I recently upgraded my Entity Framework Core project from DotNet Core 2.2 to 3.1.
I am using newtonsoft json, but I am wondering if I still need these two lines that are causing the errors. Here are those two lines:
services.AddMvc()
.AddJsonOptions(
options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
});
And here is the error:
'JsonOptions' does not contain a definition for 'SerializerSettings' and no accessible extension method
'SerializerSettings' accepting a first argument of type 'JsonOptions'
could be found
Does the new Microsoft JSON library have anything that would ignore reference loops and null values like Newtonsoft JSON does?
This is a known limitation of System.Text.Json and this feature might be addressed in .net 5 which is slated for Nov 2020 :
Reference : https://github.com/dotnet/corefx/issues/38579 and https://github.com/dotnet/corefx/issues/41002
Currently the workaround is to use Newtonsoft JSON instead . To use Newtonsoft.Json in an ASP.NET Core 3.0 MVC project :
Install the Microsoft.AspNetCore.Mvc.NewtonsoftJson package.
Update Startup.ConfigureServices to call AddNewtonsoftJson and set settings :
services.AddMvc()
.AddNewtonsoftJson(options => {
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
});

EF Core tools System.Configuration.ConfigurationManager assembly not found

I am creating a new application that is using EF Core 2 with migrations.
The application itself is .net Framework but the model is in a separate .net core 2.0 assembly. Everything is working fine I have defined a designtime context factory:
public class MyDesignTimeContextFactory : IDesignTimeDbContextFactory<MyContext>
{
public MyContext CreateDbContext(string[] args)
{
return new MyContext("Server=localhost\\SQLEXPRESS;Database=DBName;User ID=Test;Password=0000;");
}
}
And I can generate migrations and apply/revert them to the DB.
Now if I replace hardcoded connection string with a call to config file
return new MyContext(System.Configuration.ConfigurationManager.AppSettings.Get("ConnectionString");
I have an error when calling EF Core tools:
Add-Migration -Project MyProject.Model -Name Initialization
System.IO.FileNotFoundException: Could not load file or assembly 'System.Configuration.ConfigurationManager, Version=4.0.1.0 ....,
However the nuget is there and I can access ConfigurationManager in ContextFactory (not the designtime one) with no problem when launching the application itself. Looks like EF core tools are not looking for the dependencies of the model assembly...
Is there something I am missing? Maybe it is not possible to use ConfigurationManager in DesignTime context factory?
Finally the problem was in the application project. I had to add the nuget package for System.Configuration.ConfigurationManager to the .Net Framework app so the PackatManager can find it. A bit weired that it works at runtime but not in "design mode".

Cake build - NugetRestore with PackageReferences

I have a Visual Studio 2017 solution which contains .NET Standard, .NET Core, and .NET Framework projects. My .NET Framework 4.6.2 project is using PackageReferences in the .csproj file - instead of a packages.config.
This seems to be the new way of specifying NuGet packages and will allow future migration to .NET Standard 2.0 (I hope).
https://learn.microsoft.com/en-us/nuget/consume-packages/package-references-in-project-files
csproj:
<ItemGroup>
<PackageReference Include="LanguageExt.Core">
<Version>2.1.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.SqlServer.Dac">
<Version>1.0.3</Version>
VS displays cool icons:
Anyway, the solution compiles fine under Visual Studio but fails with build errors when compiling via cake.
Databases\DatabaseInstaller.cs(5,27): error CS0234: The type or namespace name 'Dac' does not exist in the namespace 'Microsoft.SqlServer' (are you missing an assembly reference?) [C:\code\Core.AcceptanceTesting\Core.AcceptanceTesting.csproj]
Are these newer "PackageReferences" supported by cake build?
Here's a segment from my cake script:
// NuGet restore packages for .NET Framework projects (and .NET Core projects)
Task("NuGet-Restore")
.IsDependentOn("Clean")
.Does(() =>
{
NuGetRestore(solutionFile);
});
// NuGet restore packages for .NET Core projects only
Task("DotNetCoreRestore")
.IsDependentOn("NuGet-Restore")
.Does(() =>
{
var settings = new DotNetCoreRestoreSettings
{
ArgumentCustomization = args => args.Append("/p:Version=" + versionPrefix + "-" + versionSuffix)
};
DotNetCoreRestore(settings);
});
// Build our solution
Task("Build")
.IsDependentOn("DotNetCoreRestore")
.Does(() =>
{
DotNetCoreBuild(
solutionFile,
new DotNetCoreBuildSettings()
{
ArgumentCustomization = args => args.Append("/p:Version=" + versionPrefix + "-" + versionSuffix),
Configuration = configuration
});
});
I downloaded your repo and got it building. Use the build definition below. Reason it works in Visual Studio is because it uses MSBuild and Nuget.exe. Don't call DotNetCoreX-commands on NET Framework.
Task("Build")
.IsDependentOn("NuGet-Restore")
.Does(() => {
MSBuild(solutionFile);
});
What version of Cake are you using? The .Net Core aliases were recently updated to reflect some changes in the API surface. What happens if you try the following:
var settings = new DotNetCoreRestoreSettings
{
ArgumentCustomization = args => args.Append("/p:Version=" + versionPrefix + "-" + versionSuffix)
};
DotNetCoreRestore(solutionFile, settings);
i.e. include the path to the Solution File.
As per this example:
https://github.com/cake-contrib/Cake.Recipe/blob/develop/Cake.Recipe/Content/build.cake#L128

Entity Framework 5.0 RC - Package Manager command 'add-migration' fails due to supposedly missing configuration type

Using Entity Framework 5.0.0 RC/EF 5.x DbContext Generator for C#/Visual Studio 2012 RC/.NET 4.0, I'm trying to enable automatic migrations in my project. I've run enable-migrations in the Package Manager Console:
PM> enable-migrations
No classes deriving from DbContext found in the current project.
Edit the generated Configuration class to specify the context to enable migrations for.
Code First Migrations enabled for project Test.
As you can see, it didn't automatically detect my DbContext derived type, but I solved this easily enough by entering the name of this type in the generated code file, Migrations/Configuration.cs.
However, the next step, the Package Manager Console command enable-migrations fails due to not finding the migrations configuration type added by the previous step.
PM> add-migration Initial
No migrations configuration type was found in the assembly 'Test'. (In Visual Studio you can use the Enable-Migrations command from Package Manager Console to add a migrations configuration).
How can I solve this?
EDIT: I found that I could specify the name of the configuration type with the parameter -ConfigurationTypeName:
PM> add-migration -ConfigurationTypeName Test.Migrations.Configuration Initial
The type 'Configuration' is not a migrations configuration type.
This still doesn't work, but at least it elucidates why add-migration bails, i.e. it thinks Test.Migrations.Configuration isn't a migrations configuration type. Does anyone have a clue as to why it isn't accepted, given that it was generated by enable-migrations? See the generated code below for reference (UserModelContainer derives from DbContext):
namespace Test.Migrations
{
using System;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;
using Test.Models;
internal sealed class Configuration : DbMigrationsConfiguration<UserModelContainer>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(UserModelContainer context)
{
// This method will be called after migrating to the latest version.
// You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data. E.g.
//
// context.People.AddOrUpdate(
// p => p.FullName,
// new Person { FullName = "Andrew Peters" },
// new Person { FullName = "Brice Lambson" },
// new Person { FullName = "Rowan Miller" }
// );
//
}
}
}
The issue turned out to be that I had installed Entity Framework 5.0.0 RC while targeting .NET framework 4.5. Due to deploying to Windows Azure, I found I had to target .NET 4.0 instead. I don't know the intricacies of NuGet, but it seems that the EF package installed for .NET 4.5 didn't work properly with my 4.0 targeting project.
After reinstalling the EF NuGet package, while targeting my project at .NET 4.0, everything works well.