.NET Core multi-project build change in tasks.json

In earlier versions of .NET Core tooling, building multiple projects was simply a matter of adding them as args in the tasks.json file.

1
2
3
4
5
6
7
8
9
   "tasks": [
        {
            "taskName": "build",
            "command": "dotnet",
            "args": [
                "./J3DI.Domain/",
                "$./J3DI.Infrastructure.EntityFactoryFx/",
                "$./J3DI.Infrastructure.RepositoryFx/",
   ...

Each directory was a child of the location with global.json, and each had its own project.json. This approach worked very well for producing multiple .NET Core libraries and their associated unit tests.

After migrating this code and changing the references to the specific .csproj files, we found that only 1 arg is allowed for the dotnet build task. If the args array contains more than one item, compilation gives

MSBUILD : error MSB1008: Only one project can be specified.

The fix is to reference the Visual Studio Solution File (.sln) in the args.

 

1
2
3
4
5
6
7
    "tasks": [
        {
            "taskName": "build",
            "args": [
                "${workspaceRoot}/J3DI.sln"
            ],
    ...

Good News: There’s still a way to build multiple projects by encapsulating them in a .sln file.

Bad News: Visual Studio required. (IOW, ever tried manually creating or managing a .sln?)

.NET Core: No Sophisticated Unit Testing, Please!

In my previous post, I wrote about .NET Core’s limitation regarding directory depth.  I explained that I’m trying to create several related Domain-Driven Design packages for J3DI.  One of .NET Core’s strengths is the ability to use exactly what’s needed.  Apps don’t need the entire .NET Framework; they can specify only the packages / assemblies necessary to run.  Since I want J3DI to give developers this same option — only use what is needed — I broke the code down in to several aspects.

I’ve enjoyed using Microsoft’s lightweight, cross-platform IDE, Visual Studio Code (VSCode), with this project. It has a nice command palette, good Git integration, etc. But, unfortunately, it appears that VSCode will only execute a single test project.

For context, here’s my tasks.json from the .vscode directory:

{
   "version": "0.1.0",
   "command": "dotnet",
   "isShellCommand": true,
   "args": [],
   "tasks": [
      {
         "taskName": "build",
         "args": [ 
            "./J3DI.Domain", 
            "./J3DI.Infrastructure.EntityFactoryFx",
            "./Test.J3DI.Common", 
            "./Test.J3DI.Domain", 
            "./Test.J3DI.Infrastructure.EntityFactoryFx" 
         ],
         "isBuildCommand": true,
         "showOutput": "always",
         "problemMatcher": "$msCompile",
         "echoCommand": true
     },
     {
         "taskName": "test",
         "args": [
            "./Test.J3DI.Domain", 
            "./Test.J3DI.Infrastructure.EntityFactoryFx"
         ],
         "isBuildCommand": false,
         "showOutput": "always",
         "problemMatcher": "$msCompile",
         "echoCommand": true
      }
   ]
}

Notice how args for the build task includes 5 sub-directories. When I invoke this build task from VSCode’s command palette, it builds all 5 sub-directories in order.

Now look at the test task which has 2 sub-directories specified. I thought specifying both would execute the tests in each. Maybe you thought so, too. Makes sense, right? Well, that’s not what happens. When the test task is invoked from VSCode, the actual command invoked is:

running command> dotnet test ./Test.J3DI.Domain ./Test.J3DI.Infrastructure.EntityFactoryFx
...
error: unknown command line option: ./Test.J3DI.Infrastructure.EntityFactoryFx

(BTW, use the echoCommand in the appropriate task section to capture the actual command)

Hmmmm, maybe the build task works differently? Nope. Here’s its output:

running command> dotnet build ./J3DI.Domain ./J3DI.Infrastructure.EntityFactoryFx ./Test.J3DI.Common ./Test.J3DI.Domain ./Test.J3DI.Infrastructure.EntityFactoryFx

Ok, so it seems that dotnet build will process multiple directories, but dotnet test will only process one. To be clear, this is not a bug in VSCode — it’s just spawning the commands as per tasks.json. So I thought maybe multiple test tasks could work. I copied the test task into a new section of tasks.json, removed the first directory from the new section, and remove the second directory from the original section. Finally, I set isTestCommand for both sections.

{
   "taskName": "test",
   "args": [ "./Test.J3DI.Domain" ],
...
   "isTestCommand": true
}
,
{
   "taskName": "test",
   "args": [ "./Test.J3DI.Infrastructure.EntityFactoryFx" ],
...
   "isTestCommand": true
}

I hoped this was the magic incantation, but I was once again disappointed. Hopefully Microsoft will change dotnet’s test task to behave like the build task. Until then, we’re stuck using shell commands like the one shown in this stackoverflow question.