Matt Ward

.NET Core Support in Visual Studio for Mac 7.5

New Features

  • .NET Core 2.1 SDK support
    • .NET Core 2.1 SDK project templates
    • HTTPS development certificate support
    • .NET Core global tools added to PATH on startup
  • .NET Core location can now be configured
  • Xamarin.Forms project templates now use .NET Standard projects
  • Performance improvements when using projects with many files
  • .NET Core templating engine has been updated
  • Improved support for Xamarin.Forms
  • Item templates are now supported with the .NET Core templating engine

More information on all the new features and changes in Visual Studio for Mac 7.5 can be found in the release notes.

.NET Core 2.1 SDK support

Visual Studio for Mac 7.5 includes support for the .NET Core 2.1 SDK which is currently available as a release candidate. The following sections will look into the support provided by Visual Studio for Mac 7.5 for the .NET Core 2.1 SDK.

.NET Core 2.1 SDK project templates

If .NET Core 2.1.300 SDK is installed then the .NET Core 2.1 project templates will be available in the New Project dialog.

New Project dialog - .NET Core 2.1 target framework option

The .NET Core 2.1 project templates are not included with Visual Studio for Mac and will be searched for in the 2.1.300 SDK templates directory.

/usr/local/share/dotnet/sdk/2.1.300-rc1-008673/Templates/

The project templates for .NET Core 2.0 and 1.1 are currently still being shipped with Visual Studio for Mac.

HTTPS development certificate support

ASP.NET Core 2.1 projects use HTTPS by default. In order to be able to run ASP.NET Core 2.1 projects with HTTPS a development certificate needs to be installed. Visual Studio for Mac will detect if the development certificate is missing and offer to install it when you run an ASP.NET Core 2.1 project that uses HTTPS.

HTTPS development certificate not installed message

Visual Studio for Mac will use the dotnet dev-certs tool to check if the HTTPS development certificate is installed and trusted.

dotnet dev-certs https --trust --check

Installing the HTTPS certificate requires administrator privileges so you may be prompted for your username and password after clicking the Yes button. Currently the prompt for credentials shows mono-sgen64 wants to make changes. In the future this will show a custom message indicating that the credentials are required to install the HTTPS development certificate.

Mono sgen administrator dialog prompt

After entering your credentials the following command is run as administrator.

dotnet dev-certs https --trust

After the certificate is installed the ASP.NET Core 2.1 project will be opened in the default browser using HTTPS.

ASP.NET Core 2.1 project open in browser using HTTPS

Running dotnet dev-certs https —trust to install and trust the certificate needs to be done with administrator privileges with the user id 0. To do this Visual Studio for Mac does the following:

  1. Launches a separate custom console app.
  2. The console app uses the AuthorizationExecuteWithPrivileges Mac API provided by Xamarin.Mac to launch itself as again as administrator. It is not possible to run dotnet as administrator initially since it requires the user id to be set to 0, which is what happens when you use sudo dotnet, and this can only be done when running with administrator privileges. So the console app is launched again but this time with administrator privileges.
  3. The console app, now being run with administrator privileges, will use setuid to set the current user id to 0.
  4. The console app then runs dotnet dev-certs https —trust which will install and trust the HTTPS development certificate.

The dotnet dev-certs https —trust command will add two localhost certificates. You can see these by opening the Keychain Access application and searching for localhost.

localhost certificate created by dotnet dev-certs in Keychain Access application

If the HTTPS development certificate is found to be valid and trusted then this will be remembered for the current Visual Studio for Mac session and a check will not be run again during the current session.

.NET Core global tools added to path on startup

The .NET Core SDK 2.1 supports installing global tools. These tools are .NET Core console apps that are available as NuGet packages and can be installed and used from the command line. To be able to use these tools with the dotnet command line the ~/.dotnet/tools directory needs to be added to the PATH environment variable. The path to these global tools is now added to Visual Studio’s PATH environment variable when it starts.

Prompt to install .NET Core 2.1 SDK if not installed

If a .NET Core 2.1 project is opened and .NET Core 2.1.300 SDK is not installed then a dialog will be shown allowing the SDK to be downloaded. The project in the Solution window will show an error icon indicating that the .NET Core 2.1 SDK is not installed.

Launching a browser when running an ASP.NET Core 2.1 project

The .NET Core SDK 2.1 project templates for ASP.NET Core specify the https and http urls in the launchSettings.json file by using the applicationUrl property.

    "MyAspNetCore21Project": {
        "commandName": "Project",
        "launchBrowser": true,
        "applicationUrl": "https://localhost:5001;http://localhost:5000",
        "environmentVariables": {
            "ASPNETCORE_ENVIRONMENT": "Development"
        }
    }

With earlier .NET Core 2.1 preview SDKs this was defined in the ASPNETCORE_URLS environment variable. The full applicationUrl property was used unmodified when running the ASP.NET Core 2.1 project and resulted in an invalid url being used causing the AspNetCoreExecutionHandler to log a warning and not opening the browser. Now the first url in the applicationUrl is used if there are multiple urls.

Support ASPNETCORE_URLS when launching the browser

If the launchSettings.json does not define an applicationUrl then Visual Studio for Mac will fallback to checking the environment variable defined for ASPNETCORE_URLS in the launchSettings.json file and will use the first url found there. This url will be used to launch the browser when running the project.

An example launchSettings.json that was used in the .NET Core 2.1 preview SDKs is shown below.

"MyProject": {
  "commandName": "Project",
  "launchBrowser": true,
  "environmentVariables": {
    "ASPNETCORE_ENVIRONMENT": "Development",
    "ASPNETCORE_URLS": "https://localhost:5001;http://localhost:5000"
  }
}

Compared with the .NET Core SDK 2.0.

"MyProject": {
  "commandName": "Project",
  "launchBrowser": true,
  "environmentVariables": {
    "ASPNETCORE_ENVIRONMENT": "Development"
  },
  "applicationUrl": "http://localhost:5000/"
}

Allow .NET Core location to be configured

In Preferences there is now a Projects – SDK Locations – .NET Core section that can be used to configure the location of the .NET Core command line tool (dotnet).

.NET Core location configured in preferneces

This can be used to configure Visual Studio for Mac to use a .NET Core SDK that is not installed in the default location. After this is changed the MSBuild engine hosts are recycled and all .NET Core projects are re-evaluated to ensure the new locations of any MSBuild targets are used.

If the location is invalid, or no runtimes or SDKs can be found at the configured location, a Not found error will be displayed.

Invalid .NET Core location path specified in preferences

Xamarin.Forms Project Templates now include .NET Standard projects

The Xamarin.Forms project templates, Blank Forms App and Forms App, will now create a .NET Standard 2.0 project instead of a Portable Class Library (PCL) project if .NET Standard is selected in the New Project dialog.

New Project dialog - Blank Forms - .NET Standard option

The Xamarin.Forms Class Library project template now creates a .NET Standard 2.0 project instead of a Portable Class Library project.

New Project dialog - Xamarin.Forms Class Library project

Prevent .xaml.cs file from being renamed in a .NET Core project

The Xamarin.Forms NuGet package has an MSBuild .targets file that is imported after the project items are defined. This .targets file overrides the DependentUpon property for all .xaml.cs files. This means that renaming the .xaml.cs file to be different to the .xaml file is not supported. To prevent this the Rename menu is now disabled in the Solution window for .xaml.cs files if they depend on a .xaml file.

Exclude None build action for XAML files in .NET Core projects

Recent versions of Xamarin.Forms NuGet packages exclude all .xaml files from the default None file wildcard defined by the .NET Core SDK. This exclusion is done in a .targets file which is applied after the items in the project file have been added. This means that a .NET Standard project should not use None items for .xaml files since they will be removed. To avoid this problem the None build action is excluded from the list of build actions for .xaml files. This list of build actions is available when right clicking the file in the Solution window and in the Properties window when the file is selected.

Dependent files now renamed on renaming parent file in the Solution window

When a file is renamed in the Solution window the dependent files will also be renamed if they start with the same name as the parent file. This avoids problems with XAML files since a different name for the .xaml file and the associated .xaml.cs file is not supported.

Improve project load times for projects with many files

Opening a .NET Core project that contained many files that were not excluded, such as a .NET Core console project that has a node_modules directory, could take a long time to load.

Some performance improvements have been made to speed up the loading of .NET Core projects. For a .NET Core console project that had a node_modules directory containing around 17000 files the initial project load time which was taking around 70-80 seconds and now it takes around 20 seconds. Visual Studio 2017 on Windows takes around 15-20 seconds to load the same project before it is visible in the Solution Explorer window.

The performance improvements include:

  1. Adding a faster project item lookup used when finding an existing project item on loading the project.
  2. Updating the existing project items is now faster avoiding iterating over the existing items.
  3. Evaluating MSBuild items is now only done when evaluating properties. Previously this was done when evaluating project configurations and run configurations. This would result in files and directories being searched multiple times when looking wildcard matches on loading the project. Now the files and directories are searched once during the initial project load.

.NET Core templating engine updated

Updated the .NET Core templating to version 1.0.0-beta3-20171117-314. This new version of the .NET Core templating engine fixes the following problems:

  1. Templates that use files with @ character in their names being generated with the @ symbol encoded.
  2. Templates that use the Guid macro and did not specify a format would cause the template generation to fail. An exception was thrown since the format was not defined. Now if the format is not defined the default format is used.

Report template creation failures when using the .NET Core templating engine

To help diagnose problems with project and item templates that use the .NET Core templating engine more detailed information about the failure is now logged in the IDE log.

Support item templates with the new templating engine

Item templates that use the .NET Core templating engine can be defined through a new extension point.

<Extension path="/MonoDevelop/Ide/ItemTemplates">
        <Template
                id="Azure.Function.CSharp.BlobTrigger"
                _overrideName="Blob Trigger"
                path="Templates/Azure.Functions.Templates.nupkg" />
</Extension>

Item templates are not currently supported in the New File dialog however there is an API that can be used by extensions to create files from these templates. This is currently used when adding a new Azure Function to a project.

Bug Fixes

Missing child package dependencies in Solution window

After creating a new ASP.NET Core project sometimes the package dependencies shown in the Solution window under the SDK folder and the NuGet folder could not be expanded to view the child dependencies.

The problem was that if the call to get the package dependencies using MSBuild was cancelled this would result an empty list of depenencies being cached. Since no package dependencies were returned the Solution window would fallback to showing the package dependencies that were listed in the project and a default top level SDK package dependency.

MSBuild wildcards being expanded on saving a project

Saving a project with a file wildcard that had a Link with MSBuild item metadata, as shown below, would result in the wildcard being removed and replaced with MSBuild items for each file included by the wildcard.

<Compile Include="**\*.cs" Exclude="obj\**">
  <Link>%(RecursiveDir)%(Filename).cs</Link>
</Compile>

The problem was that the evaluated Link property value was being compared with the unevaluated value, which did not match, resulting in the wildcard being replaced with individual MSBuild items for each file. Now if the property value contains a % character a comparison is made against the evaluated value when checking if the project item has changed.

MSBuild items added for wildcards with link metadata on saving project

A project containing the following MSBuild file wildcards would have extra MSBuild items added when the project file was saved.

<ItemGroup>
  <Compile Include="..\**\*.cs">
    <Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
  </Compile>
</ItemGroup>

On saving the project Compile update items would be added for each file included by the file wildcard.

<ItemGroup>
  <Compile Update="..\Test\Class1.cs">
    <Link>Class1.cs</Link>
  </Compile>
</ItemGroup>

This problem is similar to the previous problem where the evaluated Link value was being compared with the unevaluated value, which did not match, resulting MSBuild update items being added to the project when it was saved. Now if the property value contains a % character a comparison is made against the evaluated value when checking if the project item has changed.

TargetFramework changed on saving project

Adding a file to an SDK style project that targeted Tizen 4.0 would result in the TargetFramework changing from tizen40 to tizen4.0. Now the original framework identifier name is not modified and if the version of the framework changes then the version will be dotted or contain only numbers based on the format that was originally used in the project file.

ASP.NET Core file templates modifying project file

Adding a new .cshtml file from a file template to an ASP.NET Core project would modify the project file when it should not have been modified. The problem was the files were added as None items whilst .cshtml are Content items. The project file would contain the following after adding a new cshtml file from a template:

<ItemGroup>
  <Content Remove="Views\Index.cshtml" />
</ItemGroup>
<ItemGroup>
  <None Include="Views\Index.cshtml" />
</ItemGroup>

Another problem was that the Razor Page with view model file template specifies a DependentUpon property so this was added to the project file. This would result in the .cshtml and .cs files being nested whilst the other .cshtml and .cs files created with the initial ASP.NET Core project template were not nested. The project file would include the following:

<ItemGroup>
  <Compile Update="Views\Index.cshtml.cs">
    <DependentUpon>Index.cshtml</DependentUpon>
  </Compile>
</ItemGroup>

The .NET Core SDK does not indicate that .cshtml and .cs files are dependent on each other so they are not currently nested in the Solution window. New .cshtml files created from these updated file templates will now not be nested in Solution window.

XAML files not nested after editing project file in editor

Adding a new content page with xaml to a .NET Standard project, then excluding the files from the project, but not deleting it, then editing the project file and commenting out the MSBuild remove items, would then result in the xaml files not being nested in the Solution window. The problem was that the MSBuild update item for the .xaml.cs file, defined by the Xamarin.Forms default msbuild items, was being removed from the MSBuild project in memory. This MSBuild update item had the DependsOn property defined so this information was lost on reloading the project. Now a check is to made to ensure only update items that exist in the original project file are removed.

MSBuild item added for XAML file copied to a .NET Standard project

When copying a .xaml file from a Portable Class Library project to a .NET Standard project an MSBuild include item for the file would be added if the .xaml file did not have the default metadata properties defined by Xamarin.Forms. Now .NET Core projects opt-in to supporting items not being excluded if they are missing MSBuild item metadata which prevents an MSBuild include item added for the .xaml file.

Duplicate XAML file build error when copying file to a .NET Standard project

Copying a .xaml file from a Portable Class Library project to a .NET Standard project would result an MSBuild item for the .xaml file to the project causing it to not build due to a duplicate .xaml file.

Now when a xaml file is copied into a .NET Standard project, and it is missing properties that are included in by an update wildcard, an MSBuild item will not be added to the project.

MSBuild remove item not added for .xaml.cs file

With a .NET Core project, containing a single .xaml file and a dependent .xaml.cs file, removing but not deleting the .xaml file from the Solution window would not add an MSBuild remove item for the .xaml.cs file even though it was removed from the Solution window.

The problem was that the Xamarin.Forms NuGet package includes a Compile update item and only this was being considered when saving the project file. The default file wildcard, that includes all .cs files, provided by the .NET Core SDK was not considered. Only the last MSBuild item associated with the .xaml.cs file was being considered. If there was another .cs file in the project then the MSBuild remove item was added correctly. To avoid this all MSBuild items associated with a project item are now considered.

MSBuild remove item not removed on adding XAML file to project

When an .xaml file was removed but not deleted, and Xamarin.Forms 2.5 used, which has default MSBuild items defined, on adding the .xaml file back again to the project the EmbeddedResource remove item was not removed from the project.

The problem was that the .xaml file was being added as a None item since by default there is no build action specified for .xaml files.

Another problem was that the MSBuild remove items, defined by Xamarin.Forms that remove all .xaml files from the default None included by the .NET Core SDK, were being ignored since the file wildcards were not found.

Also an msbuild item is no longer added for an existing xaml file when it is added to the project. The Xamarin.Forms default msbuild items for .xaml files have extra metadata which were not being added to the file when it was added to the project from the file system.

Update item added on renaming xaml.cs file

When the .xaml and .xaml.cs file were renamed at the same time an MSBuild update item was added for the .xaml.cs file even though the Xamarin Forms NuGet package has a default MSBuild item that was the same as the generated MSBuild update item.

Argument null exception logged on opening .NET Core project

Opening a .NET Core project would sometimes log an unhandled ArgumentNullException. A file created event was sometimes raised before the project had finished loading and could result in a null set of items being used when checking if the new file should be added to the project. This is now handled. The files being created on project load are typically in the obj folder and would be ignored by the default file wildcards.

An unhandled exception has occured. Terminating Visual Studio? False
System.ArgumentNullException: Value cannot be null.
Parameter name: source
  at System.Linq.Enumerable.Where[TSource]
  in corefx/src/System.Linq/src/System/Linq/Where.cs:42
  at MonoDevelop.Projects.Project.OnFileCreatedExternally
in src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs:4041

NuGet Support in Visual Studio for Mac 7.5

Changes

  • Support installing NuGet packages with item templates
  • Fixed generated NuGet package files not available for code completion
  • Fixed incorrect Android target framework used when the project has Package References
  • Fixed build errors after creating a new Android project with NuGet packages
  • Missing package dependencies in Solution window

More information on all the new features and changes in Visual Studio for Mac 7.5 can be found in the release notes.

Support installing NuGet packages with item templates

Initial support for creating new files from item templates that use the .NET Core templating engine has been added. This is currently used by the Azure Functions support in Visual Studio for Mac when a new Azure Function is added to the project. Currently the New File dialog does not have support for showing these templates but there is an API that can be used by extensions to create files from these templates.

The item templates can define post actions that indicate that a NuGet package is needed. These post actions are read and the NuGet package will be installed into the project by Visual Studio for Mac.

"postActions": [
  {
    "Description": "Adding Reference to Microsoft.Azure.WebJobs.Extensions.DocumentDB Nuget package",
    "ActionId": "B17581D1-C5C9-4489-8F0A-004BE667B814",
    "ContinueOnError": "true",
    "ManualInstructions": [],
    "args": {
      "referenceType": "package",
      "reference": "Microsoft.Azure.WebJobs.Extensions.DocumentDB",
      "version": "1.2.0",
      "projectFileExtensions": ".csproj"
    }
  }

Bug Fixes

Generated NuGet package files not available for code completion

On installing a NuGet package such as Refit, which extends the CoreCompileDependsOn to generate a C# file, the generated file would not be available for code completion until the solution was closed and re-opened again.

Below is a section of the refit.targets file used by the Refit NuGet package.

<PropertyGroup>
  <CoreCompileDependsOn>
    $(CoreCompileDependsOn);
    GenerateRefitStubs;
  </CoreCompileDependsOn>
</PropertyGroup>

<Target Name="GenerateRefitStubs" BeforeTargets="CoreCompile">

  <Error Condition="'$(MSBuildRuntimeType)' == 'Core' and '$(RefitMinCoreVersionRequired)' > '$(RefitNetCoreAppVersion)' "
       Text="Refit requires at least the .NET Core SDK v2.0 to run with 'dotnet build'"
       ContinueOnError="false"
       />

  <GenerateStubsTask SourceFiles="@(Compile)" BaseDirectory="$(MSBuildProjectDirectory)"   OutputFile="$(IntermediateOutputPath)\RefitStubs.g.cs" />

  <Message Text="Processed Refit Stubs" />      

  <ItemGroup Condition="Exists('$(IntermediateOutputPath)\RefitStubs.g.cs')">
    <Compile Include="$(IntermediateOutputPath)\RefitStubs.g.cs" />
  </ItemGroup>    
</Target>

The CoreCompileDependsOn property is re-defined so the GenerateRefitsStubs MSBuild target will be run. This creates a new RefitStubs.g.cs file which is included in the project by the Compile MSBuild item.

The problem was that the result of running the targets that are defined by the CoreCompileDependsOn property are cached by Visual Studio for Mac. When Refit is installed the cached result was still being returned so the generated C# file was not available for code completion. To fix this the project is now re-evaluated before getting the CoreCompileDependsOn property if an MSBuild import has been added or removed. Note that projects that use Package References were unaffected. Only projects that use a packages.config file were affected.

Incorrect Android target framework used when the project has Package References

Configuring an Android project so it uses the latest Android framework could result in the wrong target framework being used when building if the project used Package References. This would result in a build error similar to:

Error: Your project is not referencing the "MonoAndroid,Version=v7.1" framework. 
Add a reference to "MonoAndroid,Version=v7.1" in the "frameworks" section of your 
project.json, and then re-run NuGet restore

The problem was that the wrong target framework was being used in the project.assets.json. Running a NuGet restore was a workaround for the problem.

Now when the target framework version in project options is changed, and the project uses Package References, a NuGet restore is run after the project file is saved. This ensures the Package References work with the new target framework. This also re-generates the project.assets.json file so the build will use the correct references.

Another problem here was that configuring the Android to use the latest target framework would not result in the target framework being changed in the project model stored in memory. This could also result in the project.assets.json file being out of sync with the Android project’s target framework.

Build errors after creating a new Android project with NuGet packages

Creating a new Android project that installed NuGet packages as it was created would sometimes result in build errors that could be fixed by closing and re-opening the solution. An example build error is shown below.

Resources/values/styles.xml : error APT0000: 1: error: Error retrieving parent for item: No resource found that matches the given name 'Theme.AppCompat.Light.DarkActionBar'.
Resources/values/styles.xml : error APT0000: 2: error: Error: No resource found that matches the given   name: attr 'colorAccent'.
Resources/values/styles.xml : error APT0000: 1: error: Error: No resource found that matches the given name: attr 'colorPrimary'.
Resources/values/styles.xml : error APT0000: 1: error: Error: No resource found that matches the given name: attr 'colorPrimaryDark'.
Resources/values/styles.xml : error APT0000: 1: error: Error: No resource found that matches the given name: attr 'windowActionBar'.
Resources/values/styles.xml : error APT0000: 3: error: Error: No resource found that matches the given name: attr 'windowActionModeOverlay'.
Resources/values/styles.xml : error APT0000: 1: error: Error: No resource found that matches the given name: attr 'windowNoTitle'.
Resources/values/styles.xml : error APT0000: 3: error: Error retrieving parent for item: No resource found that matches the given name 'Theme.AppCompat.Light.Dialog'.
Resources/values/styles.xml : error APT0000: 3: error: Error: No resource found that matches the given name: attr 'colorAccent'.

The build errors varied but in each case the error was caused by a missing reference to an assembly from one of the Android Support NuGet packages installed when the project was created. The project file created would have the correct reference information but Visual Studio for Mac was building an old version of the project.

If the project was modified in memory when a build is requested this results in the unsaved project xml being given to the remote MSBuild host. In some cases this project xml was not being cleared and would result in an out of date project xml being used when building. This could occur if the MSBuild host did not have any projects loaded at the time when an attempt was made to unload the project from the host. Now the unsaved project xml is removed in all cases when the project is unloaded from the MSBuild host.

Missing package dependencies in Solution window

After creating a new ASP.NET Core project sometimes the package dependencies shown in the Solution window under the SDK folder and the NuGet folder could not be expanded to view the child dependencies.

The problem was that if the call to get the package dependencies using MSBuild was cancelled this would result an empty list of depenencies being cached. Since no package dependencies were returned the Solution window would fallback to showing the package dependencies that were listed in the project and a default top level SDK package dependency.

Language Server Protocol support in Visual Studio for Mac 7.4

A preview of support for the Language Server Protocol is now available for Visual Studio for Mac 7.4 as a separate extension.

Docker Language Server client being used in Visual Studio for Mac

A Language Server can provide support for programming language features such as:

  • Code completion
  • Find references
  • Go to definition
  • Quick fixes
  • Method signature help
  • Errors and warnings diagnostics
  • Documentation on hover
  • Document formatting
  • Rename refactoring

The Language Server Protocol provides a way for a client application, such as Visual Studio for Mac, to communicate with the Language Server in order to use the programming language features it supports.

Visual Studio Code supports the Language Server Protocol.

A preview of Language Server Protocol support in Visual Studio 2017 on Windows has also been announced.

Currently there is no support for debugging. Whilst there is a debugging protocol support for this is not currently available in Visual Studio for Mac.

The Language Server Protocol does not provide any support for compiling the code. This would need to be provided by the extension that implements the language client.

More detailed information about the Language Server Protocol can be found on the Language Server Protocol site.

The Creating a Language Client section below will take a more detailed look at how to implement a custom Language Server Client extension in Visual Studio for Mac.

Supports

  • MonoDevelop or Visual Studio Mac 7.4 or later.

Source Code

Installation

The Language Server Client extension is available to download from GitHub.

To install the extension open the Extensions Manager by selecting Extensions… from the main menu. Click the Install from file button. Select the .mpack file and then click the Open button.

The extension is also available in the Extensions Manager from the Visual Studio Extension Repository (Beta channel).

Creating a Language Client

The API provided by the Language Server Client extension follows the API defined by the Language Server Protocol extension used by Visual Studio on Windows as closely as possible.

More detailed documentation on the Language Server Client API provided by Visual Studio on Windows is available from the Microsoft docs site.

Prerequisites

The Language Server Client Extension for Visual Studio for Mac should be installed.

Also ensure you have the Addin Maker extension installed. This can be installed by selecting Extensions… from the main menu top open the Extensions Manager. Select the Gallery tab and use the text box at the top right to search for the Addin Maker extension.

Addin maker selected in Extensions Manager dialog

Click the Install button to install the Addin Maker extension.

The Addin Maker will be used to create the language client extension.

Creating an IDE Extension project

The starting point is to create an IDE Extension project. This project template is provided by the Addin Maker extension and is available from the New Project dialog, in the Other – IDE Extensions category.

IDE Extension project selected in New Project dialog

After creating the IDE Extensions project, expand the Dependencies folder to show the Extensions folder. Right click the Extensions folder and select Add Addin Reference.

IDE Extension project selected in New Project dialog

Find the MonoDevelop.LanguageServer.Client in the Add Extension Reference dialog. Select it to toggle its check box and then click the Add button to reference it.

Language Server Client extension in Add Extension Reference dialog

There are three parts to implementing a language client:

First we will take a look at enabling MEF support.

Enabling Managed Extensibility Framework Support

Registration of the language client with Visual Studio for Mac is done using the Managed Extensibility Framework (MEF) which is supported by Visual Studio for Mac.

In order to use MEF in your language client extension you need to indicate to Visual Studio for Mac that it should scan your extension for dependencies. This can be done in the extension’s .addin.xml file by adding the filename of your assembly.

1
2
3
<Extension path="/MonoDevelop/Ide/Composition">
  <Assembly file="MockLanguageExtension.dll" />
</Extension>

Content Type Definition

Your language client needs to indicate what files are supported. This is done by defining a content type definition.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using System.ComponentModel.Composition;
using Microsoft.VisualStudio.LanguageServer.Client;
using Microsoft.VisualStudio.Utilities;

namespace MockLanguageExtension
{
  #pragma warning disable CS0649 // Field is never assigned to.

  public class FooContentDefinition
  {
      [Export]
      [Name("foo")]
      [BaseDefinition(CodeRemoteContentDefinition.CodeRemoteContentTypeName)]
      internal static ContentTypeDefinition FooContentTypeDefinition;

      [Export]
      [FileExtension(".foo")]
      [ContentType("foo")]
      internal static FileExtensionToContentTypeDefinition FooFileExtensionDefinition;
  }

  #pragma warning restore CS0649
}

The above content definition indicates that the .foo file extension is supported by the language client.

You can also define a filename, instead of a file extension, as supported by the language client by using the FileName attribute instead of the FileExtension attribute.

1
2
3
4
5
6
7
8
9
10
11
12
class DockerContentTypeDefinition
{
  [Export]
  [Name("docker")]
  [BaseDefinition(CodeRemoteContentDefinition.CodeRemoteContentTypeName)]
  internal static ContentTypeDefinition contentTypeDefinition;

  [Export]
  [FileName("Dockerfile")]
  [ContentType("docker")]
  internal static FileExtensionToContentTypeDefinition dockerFileDefinition;
}

You will need to add a reference to System.ComponentModel.Composition so the Export attribute can be used.

Implementing ILanguageClient

To integrate the Language Server with Visual Studio for Mac the ILanguageClient interface needs to be implemented.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.LanguageServer.Client;
using Microsoft.VisualStudio.Threading;
using Microsoft.VisualStudio.Utilities;

namespace MockLanguageExtension
{
  [ContentType("foo")]
  [Export(typeof(ILanguageClient))]
  public class FooLanguageClient : ILanguageClient
  {
      public IEnumerable<string> ConfigurationSections => null;

      public object InitializationOptions => null;

      public IEnumerable<string> FilesToWatch => null;

      public string Name => "Foo Language Extension";

      public event AsyncEventHandler<EventArgs> StartAsync;
      public event AsyncEventHandler<EventArgs> StopAsync;

      public async Task OnLoadedAsync()
      {
          await StartAsync?.InvokeAsync(this, EventArgs.Empty);
      }

      public Task<Connection> ActivateAsync(CancellationToken token)
      {
          var info = new ProcessStartInfo();
          var programPath = Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), "server", @"LanguageServer.UI.exe");
          info.FileName = "mono";
          info.Arguments = programPath;
          info.WorkingDirectory = Path.GetDirectoryName(programPath);
          info.UseShellExecute = false;
          info.RedirectStandardInput = true;
          info.RedirectStandardOutput = true;

          var process = new Process();
          process.StartInfo = info;

          Connection connection = null;

          if (process.Start())
          {
              connection = new Connection(process.StandardOutput.BaseStream, process.StandardInput.BaseStream);
          }

          return Task.FromResult(connection);
      }
  }
}

The class that implements the ILanguageClient interface needs to indicate it supports the content types that you have defined, and it also needs to indicate that it implements the ILanguageClient by using the Export attribute.

1
2
[ContentType("foo")]
[Export(typeof(ILanguageClient))]

The language client should return a unique description for the ILanguageClient.Name property.

The two methods that should be implemented are:

OnLoadedAsync is called when Visual Studio for Mac has loaded your extension. To activate your Language Server you need to call StartAsync. The simplest approach is to call StartAsync in the OnLoadedAsync method.

1
2
3
4
 public async Task OnLoadedAsync()
  {
      await StartAsync?.InvokeAsync(this, EventArgs.Empty);
  }

Calling StartAsync will cause Visual Studio for Mac to call the ILanguageClient’s ActivateAsync method. This is where you can start the Language Server.

The ActivateAsync method should return a Connection object with the streams that will be used to communicate with the Language Server. Standard input and output streams are supported as well as sockets.

1
var connection = new Connection(process.StandardOutput.BaseStream, process.StandardInput.BaseStream);

The first time you try to run and debug your language client extension you will see an error in the Application Output similar to:

1
2
3
WARNING: The add-in 'MockLanguageExtension,1.0' could not be updated because some of its 
dependencies are missing or not compatible:
  missing: MonoDevelop.LanguageServer.Client,0.1

The Addin Maker runs your language client extension using its own extension database. The MonoDevelop.LanguageServer.Client extension needs to be installed into this separate database in order to be able to run and debug your language client extension.

To do this run your language client extension project in Visual Studio for Mac and install the Language Server Client extension using the Extensions Manager in the instance of Visual Studio for Mac that is started. Then stop debugging and re-run your extension project again, and your language client should now be used when you open a supported file.

The content type registration and the ILanguageClient implementation is the minimum that is needed in order to integrate your Language Server with Visual Studio for Mac. Now let us take a look at other optional things that can be implemented.

Receiving Custom Messages

Your Language Server may support messages that are not part of the standard Language Server Protocol.

In order to support receiving custom messages the class that implements ILanguageClient should also implement the ILanguageClientCustomMessage interface. The CustomMessageTarget property should return an object that will receive the messages.

1
2
3
4
5
6
7
public object CustomMessageTarget => new CustomMessageTarget ();
public object MiddleLayer => null;

public Task AttachForCustomMessageAsync(JsonRpc rpc)
{
  return Task.CompletedTask;
}

An example CustomMessageTarget class is shown below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using Newtonsoft.Json.Linq;
using StreamJsonRpc;

namespace MockLanguageExtension
{
  public class CustomMessageTarget
  {
      [JsonRpcMethod("test/customNotification")]
      public void OnCustomNotification(JToken arg)
      {
          // Handle custom message from the Language Server.
      }
  }
}

Sending Custom Messages

To send custom messages to the Language Server the class that implements the ILanguageClient interface should also implement the ILanguageClientCustomMessage interface.

The AttachForCustomMessageAsync method should save the JsonRpc object passed and then you can use the JsonRpc object to send custom messages to the Language Server.

1
2
3
4
5
6
7
8
9
10
11
12
13
 JsonRpc rpc;

  public Task AttachForCustomMessageAsync(JsonRpc rpc)
  {
      this.rpc = rpc;
      return Task.CompletedTask;
  }

  public async Task SendMessageToServer()
  {
      string text = await rpc.InvokeWithParameterObjectAsync<string>("GetText");
      MessageService.ShowMessage("Text from language server:", text);
  }

Middle Layer

The ILanguageClientCustomMessage defines a MiddleLayer property. An object returned from the MiddleLayer property can be used to intercept messages sent to and received from the Language Server. The MiddleLayer object can implement the following interfaces:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
using System.Threading.Tasks;
using Microsoft.VisualStudio.LanguageServer.Client;
using Microsoft.VisualStudio.LanguageServer.Protocol;

namespace MockLanguageExtension
{
  class MiddleLayerProvider : ILanguageClientCompletionProvider
  {
      public Task<object> RequestCompletions(
          TextDocumentPositionParams param,
          Func<TextDocumentPositionParams, Task<object>> sendRequest)
      {
          return sendRequest(param);
      }

      public async Task<CompletionItem> ResolveCompletion(
          CompletionItem item,
          Func<CompletionItem, Task<CompletionItem>> sendRequest)
      {
          return await sendRequest(item);
      }
  }
}

Note that currently not all the Language Server messages can be intercepted.

The full source code to the sample Language Server Client Extension created whilst writing this blog post is available on GitHub

There are other examples included with the Language Server Client extension source code on GitHub, however these are not standalone and are compiled with the Language Server Client extension.

.NET Core Support in Visual Studio for Mac 7.4

Changes

  • Solution window detects file system changes outside Visual Studio for Mac
  • Projects with unknown target frameworks can now be loaded
    • MSBuild SDK Extras is now supported without requiring an extra extension to be installed
    • Tizen.NET projects are now supported
  • Fixed xUnit test messages not being displayed
  • ASP.NET Core minified files are no longer formatted
  • Support target framework defined in another MSBuild property
  • Show SDK information before dependencies are restored
  • Fixed failure to add new file when the default project namespace contains only numbers
  • Fixed remove item not added for .xaml.cs file
  • Fixed incorrect project updates when moving a file

More information on all the new features and changes in Visual Studio for Mac 7.4 can be found in the release notes.

Solution window detects file system changes

Files created in the project directory, or a subdirectory, outside Visual Studio for Mac are now added to the project and appear in the Solution window automatically.

File added and removed from command line - Solution window updated

Deleting project files and directories will remove the files from the Solution window. The Solution window will also update after a file or a directory is renamed outside Visual Studio for Mac.

Allow unknown target framework projects to be loaded

The target framework of an SDK style project is no longer restricted. Previously Visual Studio for Mac would fail to load an SDK style project unless its target framework was .NET Standard, .NET Core App or .NET Framework.

This allows Tizen projects to be loaded without the error message “Project does not support framework ‘Tizen,Version=v4.0’” being displayed. Tizen projects have a Tizen.NET package reference which imports an MSBuild .props file that defines the Tizen target framework.

The MSBuild.Sdk.Extras NuGet package is now supported so SDK style projects can use target frameworks that this NuGet package supports, such as Xamarin.iOS and MonoAndroid.

On building a project with an unknown target framework, that is not defined by any used NuGet package references, a build error that indicates the framework is not supported will occur:

The TargetFramework value 'test1.0' was not recognized.

NuGet restore will also fail for an unknown target framework with a message indicating the framework is invalid.

Bug Fixes

Fix xUnit test messages not displayed

xUnit tests support an ITestOutputHelper interface which can be passed to the constructor of the test. This has a WriteLine method which can be used to output messages whilst running the test. When this was used the text displayed in Visual Studio for Mac’s Test Results window was:

Microsoft.VisualStudio.TestPlatform.ObjectModel.TestResultMessage

Now the text from the message is shown in the Tests Results window.

Support target framework defined in another MSBuild property

An SDK style project that defined the element to be another MSBuild property would fail to restore.

In the example below the property TheFramework is defined in the Frameworks.props file.

<Project Sdk="Microsoft.NET.Sdk">
  <Import Project="Frameworks.props" />
  <PropertyGroup>
    <TargetFrameworks>$(TheFramework)</TargetFrameworks>
  </PropertyGroup>
</Project>

The unevaluated MSBuild property value was used and would result in the NuGet package restore failing.

Now the evaluated property value is used when restoring dependencies.

ASP.NET Core minified files and map files are no longer formatted

On creating a new ASP.NET Core project the minified files were being re-formatted and were no longer minified. Now the .min.css, .min.js and .map files are excluded from being re-formatted when a new ASP.NET Core project is created.

Fixed failure to add a new file when the default project namespace contains only numbers

If a project has a default namespace of ‘1’ then adding a new C# file from a template would throw a null reference exception. The problem was that the sanitized namespace for the project’s default namespace was null.

Show SDK information before dependencies are restored

When a new .NET Core project is created the Dependencies – SDK folder would show no items until the NuGet package restore completed. Now the SDK dependency is shown whilst the dependencies are being restored.

Fixed remove item not added for .xaml.cs file

When a new content page with xaml file was added and then removed, but not deleted, a remove item was not added for the .xaml.cs file.

Fixed incorrect project updates when moving a file

Moving a Resource file from one folder to another would not update the project file correctly. Either the project file would not be modified or the file would be removed.

One problem was that on moving a clone is taken of the original item and the associated MSBuild item was copied but was still referring back to the original location. Another problem was that an incorrect match was being made when looking for remove items resulting in the wrong files being removed from the project.

Fixed being unable to use NUnit in a .NET Core test project

The problem was that the NUnit test provider, which supports running NUnit tests for non .NET Core projects, was finding a PackageReference for NUnit, and then trying to load the tests for the .NET Core project and failing. To fix this the NUnit test provider now ignores .NET Core projects so the VS Test provider will load the tests for the project.

NuGet Support in Visual Studio for Mac 7.4

Changes

  • Support NuGet RestoreProjectStyle MSBuild Property
  • .NET Core xUnit tests not displayed if NuGet packages not cached
  • No tests displayed when project uses a NUnit PackageReference
  • NuGet MSBuild imports not removed when migrating to project.json

More information on all the new features and changes in Visual Studio for Mac 7.4 can be found in the release notes.

Support RestoreProjectStyle MSBuild property

If a project sets the RestoreProjectStyle property to be PackageReference then the project will be restored as though it has PackageReferences even if it does not have any.

<RestoreProjectStyle>PackageReference</RestoreProjectStyle>

This fixes runtime problems when a project references a .NET Standard project that has PackageReferences. Without the RestoreProjectStyle set the assemblies from the NuGet packages are not copied to the output directory and would have to be added to the main project.

Bug Fixes

.NET Core xUnit tests not displayed if NuGet packages are not in local NuGet cache

If the NuGet packages that contain the VS Test adapters were not available in the local machine’s NuGet package cache then the Unit Tests window would not show any tests after the NuGet packages were restored and the project was compiled.

Visual Studio for Mac would not initially find any test adapter dlls and would not attempt to discover any tests for the project after the NuGet packages were downloaded into the NuGet package cache.

Now after the NuGet package restore has completed the check for a VS Test adapter is now re-run.

No tests displayed when a project uses a NUnit PackageReference

The Unit Tests window would not show any unit tests when a non .NET Core project contained a NUnit PackageReference. Visual Studio for Mac was looking for a PackageReference that contained ‘nunit.framework’ and was not finding the NUnit NuGet package reference.

NuGet MSBuild imports not removed when migrating to project.json

When a Portable Class Library project was migrated to use a project.json file the MSBuild imports added by NuGet were not removed. These imports are added by NuGet into the generated ProjectName.nuget.props and ProjectName.nuget.targets files on restoring a project.json file. Leaving the import in the project file would result in the import being used twice. When a PCL project that used Xamarin.Forms was migrated to project.json the project would fail to compile with the error:

Error XF001: Xamarin.Forms targets have been imported multiple times.
Please check your project file and remove the duplicate import(s).

Now on migrating to project.json the MSBuild imports added by NuGet packages to the project are removed.

Fix unhandled exception when searching for packages

An unhandled exception was being logged if a package source returned an error or the package source url was invalid. This was because a task was not being observed when the package sources were being used.

.NET Core Support in Visual Studio for Mac 7.3

Changes

  • VSTest Console Runner now included with Visual Studio for Mac
    • Allows xUnit tests to be supported for non .NET Core projects
  • Renamed ASP.NET Core Project Templates
  • New ASP.NET Core F# Project Templates Added
  • Support Backslash in Project Template Primary Output Path
  • Support NuGet Restore MSBuild Properties
    • RestoreAdditionalProjectFallbackFolders
    • RestoreAdditionalProjectSources
    • RestoreFallbackFolders
    • RestorePackagesPath
    • RestoreSources
  • Fixed transitive project references not supported

More information on all the new features and changes in Visual Studio for Mac 7.3 can be found in the release notes

VSTest Console Runner

Previous versions of Visual Studio for Mac would use dotnet vstest, included with the .NET Core SDK, to run unit tests for .NET Core projects. Now Visual Studio for Mac includes the VSTest Console runner and uses that instead of using the .NET Core SDK.

The standalone VSTest Console runner allows other project types, not just .NET Core projects, to be supported. Visual Studio for Mac can now run xUnit tests for .NET Framework projects. Previously only NUnit was supported.

Let us take a look at using xUnit in a .NET Framework project.

First create a .NET Framework Library project by opening the New Project dialog and selecting Library from the Other – .NET – General category.

Install the following NuGet packages into the project.

  • xunit
  • xunit.runner.visualstudio

Edit MyClass.cs and add some xUnit tests, as shown below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

using Xunit;

namespace xUnitTests
{
  public class MyClass
  {
      [Fact]
      public void PassingTest()
      {
          Assert.True(true);
      }

      [Fact]
      public void FailingTest()
      {
          Assert.False(true);
      }
  }
}

Building the project should then show the xUnit tests in the Unit Tests window.

xUnit tests in Unit Tests window

Note that, due to a bug in Visual Studio for Mac, the tests may not appear in the Unit Tests window if the xunit.runner.visualstudio was not available in the local machine’s NuGet package cache when it was added to the project. Closing and re-opening the solution should allow the tests to be discovered.

The tests can then be run or debugged in the usual way.

Currently MSTest is not yet supported in .NET Framework projects. The tests are discovered but they fail to run with an access denied error message:

An exception occurred while invoking executor 'executor://mstestadapter/v2': 
Access to the path "/TestResults" is denied.

Renamed ASP.NET Core Project Templates

The ASP.NET Core template names displayed in the New Project dialog have been changed to be more consistent with Visual Studio on Windows.

  • ‘ASP.NET Core Web App (Razor Pages)’ renamed to ‘ASP.NET Core Web App’
  • ‘ASP.NET Core Web App’ renamed to ‘ASP.NET Core Web App (MVC)’

Visual Studio uses (Model-View-Controller) but the shorter MVC is used by Visual Studio for Mac.

New ASP.NET Core F# Project Templates Added

The following ASP.NET Core F# project templates are now available from the New Project dialog.

  • ASP.NET Core Empty
    • .NET Core 1.x and 2.0
  • ASP.NET Core Web API
    • .NET Core 2.0 only

Support Backslash in Project Template Primary Output Path

The template.json file used by the new templating engine uses a primaryOutputs property for projects and files. If the paths used contained backslashes then the project was not added to the solution.

1
2
3
4
"primaryOutputs": [
  { "path": "Library1\\Library1.csproj" },
  { "path": "Library2\\Library2.csproj" }
]

Now the paths have the backslashes replaced with forward slashes if the current platform does not support backslash as a path separator.

Support RestoreAdditionalProjectFallbackFolders MSBuild Property

The RestoreAdditionalProjectFallbackFolders MSBuild property is read and appended to the list of fallback folders stored in the project.assets.json file. The .NET Core 2.0 SDK will set this MSBuild property to point to the NuGet package fallback folder that is installed with the SDK. This will be used to resolve NuGet packages first before downloading them to the ~/.nuget/packages folder.

Support RestoreAdditionalProjectSources MSBuild Property

The RestoreAdditionalProjectSources MSBuild property can be used to add additional package sources to the existing list of sources used to resolve packages.

Support RestoreFallbackFolders MSBuild Property

The RestoreFallbackFolders MSBuild property can be used by project that uses PackageReferences to define a set of package fallback folders that will override any specified in the NuGet.Config file. It can also be used to clear any pre-defined fallback folders by specifying ‘clear’ as its value. Note that this value does not affect any folders defined by RestoreAdditionalProjectFallbackFolders which will be appended even if RestoreFallbackFolders is set to ‘clear’.

Support RestorePackagesPath MSBuild Property

The RestorePackagesPath MSBuild property can be used to override the global packages folder location when a project uses a PackageReference.

Support RestoreSources MSBuild property

The RestoreSources MSBuild property can be used to override the sources defined by any NuGet.Config file. Any sources defined in the RestoreAdditionalProjectSources MSBuild property will still be appended to the list of sources if RestoreSources is defined.

Bug Fixes

Fixed Transitive Project References not supported

With three .NET Core projects, LibC referencing LibB referencing LibA, the types defined by LibA were not available to LibC unless it was directly referencing LibA. In Visual Studio for Mac 7.3 the types defined by LibA are available to LibC without LibC directly referencing LibA.

Portable Class Library projects can now be referenced by .NET Core projects

Portable Class Library (PCL) projects could not be referenced by .NET Core projects or .NET Standard projects. The Edit References dialog would show “Incompatible target framework” for the PCL project when trying to add the reference.

Visual Studio for Mac now has the same behaviour as Visual Studio on Windows where a .NET Standard project can reference any PCL project.

Fixed MSBuild Update item not removed from project

If a file was deleted from a project, or removed without deleting, and the file was the last file for a particular wildcard include, the Update item for the file was not being removed from the project.

Fixed MSBuild Remove item not added when Update item exists

With a project that contained a single .cs file, and that file had an Update item defined, when the file was removed from the project, without deleting it, a Remove item was not being added to the project for the file.

Fixed Remove item not being added when file excluded from project

When the last file was removed from the project, but not deleted, an MSBuild Remove item was not added to the project for the file.

  1. Create a .NET Standard 2.0 project.
  2. Right click Class1.cs and select Remove.
  3. Select Remove from Project in the dialog that opens.
  4. Close and re-open solution.

The Class1.cs file was still shown in the Solution window when it should have been removed. The project file did not have a Compile remove item for Class1.cs when it should have been added:

<Compile Remove="Class1.cs" />

Deleting a XAML file left an MSBuild Remove item in project file

When a .xaml file in a project was deleted the associated Remove MSBuild item, if it was present, was not being removed from the project file.

  1. Create a new .NET Standard 2.0 project.
  2. Add Xamarin.Forms 2.3 NuGet package.
  3. Add a new Content Page with Xaml file using the New File dialog.
  4. In the Solution window select the .xaml file and delete it.

All MSBuild items associated with the .xaml file should have been removed from the project file but instead a None item would remain.

<None Remove="MyPage.xaml" />

Fix MSBuild remove item not added when adding a XAML file

Adding a new .xaml file to a project was not adding a None Remove item for the .xaml file to remove it from the default wildcard include for all files.

<None Remove="MyNewPage.xaml" />

On reloading the solution the Solution window would show two .xaml files – one EmbeddedResource item and one None item.

Fixed MSBuild condition evaluation when using Czech locale

With the primary operating system language set to Czech, creating a new .NET Core project would result in the project having a target framework of net461.

The problem was that Single.TryParse was returing true for an empty string when the machine’s culture was ‘cs-CZ’. This was causing the MSBuild condition evaluation to be treated as a boolean comparison incorrectly in some cases. The condition below would return false even though the property was not defined and both sides of the condition were empty strings:

<PropertyGroup Condition="'$(TargetFrameworkIdentifier)' == ''">

This was causing the TargetFrameworkIdentifier to not be set for .NET Core projects so the default of .NETFramework was being used.

Re-evaluate AppliesTo condition on capability change

Fixed the AppliesTo attribute not attaching a project extension to a project after a NuGet package restore enabled a project capability. The AppliesTo attribute allows a project extension to be associated to a project based on its capabilities.

If the project extension uses an AppliesTo attribute which is initially false and then a new project capability is added, and the project is re-evaluated, the AppliesTo attribute is now re-evaluated. This will then cause the project extension to be attached to the project. If the project extension was attached to the project and the project capability is removed then the project extension will now be removed when the project is re-evaluated.

Fixed being unable to run a new Azure Functions project

Creating a new Azure Functions project would result in being unable to run the project until the solution was closed and re-opened again. After the NuGet packages are restored the project can be run but this information was not updated in Visual Studio for Mac.

Now after a NuGet package restore, when re-evaluating the project, the solution startup item is updated if there is no startup item already defined.

When the project capability is removed, due to a NuGet package being uninstalled, and the project can no longer be run the startup item will be updated if it was previously set to be this project.

Fix generated NuGet files being imported twice

The ProjectName.nuget.g.targets and ProjectName.nuget.g.props, that are generated for .NET Core projects in the base intermediate directory, were being imported twice. Once by Microsoft.Common.props, that is provided with Mono, and once again by Visual Studio for Mac.

Importing these files twice was causing a duplicate file to be added to the project information held in memory by Visual Studio for Mac when Xamarin.Forms 2.4 was used and no .NET Core SDK was installed. This would result in the content page xaml and associated C# file not being nested in the solution window.

Fixed items added to project when a new content page with XAML was created

Adding a new Xamarin.Forms content page with XAML would add an update item for the .xaml.cs file, a remove item for the xaml file, and an include item for the xaml file.

An example is Xamarin.Forms 2.4 which defines wildcard includes:

<None Remove="**\*.xaml" />
<EmbeddedResource Include="**\*.xaml" SubType="Designer" Generator="MSBuild:UpdateDesignTimeXaml" />

Which would cause a new .xaml file added to the project and saved in the project file as well as a remove for the None item even though the .xaml file was already removed from the None items.

<None Remove="MyView.xaml" />

<EmbeddedResource Include="MyView.xaml">
  <Generator>MSBuild:UpdateDesignTimeXaml"</Generator>
</EmbeddedResource>

Fix DependentUpon property being saved in project

Xamarin.Forms 2.4 defines an update item similar to:

<Compile Update="**\*.xaml.cs" DependentUpon="%(Filename)" />

When a project was saved a Compile item was added to the main project with the filename stored in the DependentUpon element. Now the evaluated DependentUpon value is treated as being the default value so it is not added to the project file.

Fix xaml.cs files not being nested

Xamarin.Forms 2.4 defines an update item similar to:

<Compile Update="**\*.xaml.cs" DependentUpon="%(Filename)" />

The DependentUpon property was being evaluated as ‘*.xaml.cs’. This was causing .xaml.cs files to not be nested in the Solution window.

Fixed build error when Xamarin.Forms 2.4 used in a .NET Standard project

If a Xamarin.Forms .NET Standard project had a .xaml file and a .xaml.cs file then the xaml.g.cs file would not be generated when the project file contained no files. The default items defined by the Xamarin.Forms NuGet package were not being imported. This then caused a build error about the InitializeComponent method not being defined.

Xamarin.Forms 2.4.0 uses default item imports which were not being included since they are conditionally imported and the MSBuildSDKsPath was not defined:

<Import Project="$(MSBuildThisFileDirectory)Xamarin.Forms.DefaultItems.props" Condition="'$(MSBuildSDKsPath)'!=''" />

MSBuild on the command line defines the MSBuildSDKsPath globally in its MSBuild.dll.config file. The MSBuild engine host, used when building a project in Visual Studio for Mac, now also defines the MSBuildSDKsPath property.

Fixed remove item added when removing a linked file

Deleting a file link in a .NET Core project would add a remove item for the file instead of removing the link from the project.

NuGet Support in Visual Studio for Mac 7.3

Changes

  • Support installing System.ValueTuple NuGet Package from Quick Fixes
  • NuGetizer 3000 – Update NuGet.Build.Packaging to version 0.2
  • Support NuGet Restore MSBuild Properties
    • RestoreAdditionalProjectFallbackFolders
    • RestoreAdditionalProjectSources
    • RestoreFallbackFolders
    • RestorePackagesPath
    • RestoreSources
  • Fixed transitive dependencies not available when using project.json

More information on all the new features and changes in Visual Studio for Mac 7.3 can be found in the release notes.

Quick Fix – Install System.ValueTuple NuGet Package

C# 7.0 introduced tuple types that may require the System.ValueTuple NuGet package to be added to the project. Visual Studio for Mac now offers to install the System.ValueTuple NuGet package if the project requires this NuGet package.

Creating a .NET Framework 4.6 project with the following code:

1
2
3
4
public (string, int) GetValues(string id)
{
  return ("Name", 25);
}

You will see error markers in the text editor. If you hover over one of these error markers you will see a Predefined type ‘System.ValueTuple`2’ is not defined or imported message.

ValueTuple type not defined text editor error tooltip

If you right click the error marker there is now a new Install Package ‘System.ValueTuple’ Quick Fix action available.

Text editor Install System.ValueTuple Package quick fix menu item

From this menu you can install the latest System.ValueTuple NuGet package or open the Add Packages dialog to search for a specific version of the System.ValueTuple NuGet package.

Text editor install latest System.ValueTuple package quick fix menu item

Note that if the project is targeting .NET Framework 4.7 or .NET Standard 2.0 then the System.ValueTuple NuGet package is not required.

Also note that the official nuget.org package source needs to be available for this feature to work.

NuGetizer 3000 – Updated NuGet.Build.Packaging to version 0.2

The version of the NuGet.Build.Packaging NuGet package used by default for NuGetizer 3000 support has been updated from 0.1.276 to 0.2.0. This fixes a potential build error when building with Mono 5.6.

1
2
3
4
5
6
7
Using "ReportAssetsLogMessages" task from assembly "/usr/local/share/dotnet/sdk/2.0.0/Sdks/Microsoft.NET.Sdk/build/../tools/net46/Microsoft.NET.Build.Tasks.dll".
Task "ReportAssetsLogMessages"
/usr/local/share/dotnet/sdk/2.0.0/Sdks/Microsoft.NET.Sdk/build/Microsoft.PackageDependencyResolution.targets(323,5): error MSB4018: The "ReportAssetsLogMessages" task failed unexpectedly. [RefactoringEssentials/RefactoringEssentials.2017/RefactoringEssentials.csproj]
/usr/local/share/dotnet/sdk/2.0.0/Sdks/Microsoft.NET.Sdk/build/Microsoft.PackageDependencyResolution.targets(323,5): error MSB4018: System.TypeLoadException: Could not resolve type with token 0100005b (from typeref, class/assembly NuGet.ProjectModel.IAssetsLogMessage, NuGet.ProjectModel, Version=4.3.0.5, Culture=neutral, PublicKeyToken=31bf3856ad364e35) [RefactoringEssentials/RefactoringEssentials.2017/RefactoringEssentials.csproj]
/usr/local/share/dotnet/sdk/2.0.0/Sdks/Microsoft.NET.Sdk/build/Microsoft.PackageDependencyResolution.targets(323,5): error MSB4018: at Microsoft.NET.Build.Tasks.TaskBase.Execute () [0x00000] in <01420900fd004c128de2d2ee31bad624>:0 [RefactoringEssentials/RefactoringEssentials.2017/RefactoringEssentials.csproj]
/usr/local/share/dotnet/sdk/2.0.0/Sdks/Microsoft.NET.Sdk/build/Microsoft.PackageDependencyResolution.targets(323,5): error MSB4018: at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute () [0x00023] in <765502eb2f884ce79731edeb4b0517fb>:0 [RefactoringEssentials/RefactoringEssentials.2017/RefactoringEssentials.csproj]
/usr/local/share/dotnet/sdk/2.0.0/Sdks/Microsoft.NET.Sdk/build/Microsoft.PackageDependencyResolution.targets(323,5): error MSB4018: at Microsoft.Build.BackEnd.TaskBuilder+d__26.MoveNext () [0x0022d] in <765502eb2f884ce79731edeb4b0517fb>:0 [RefactoringEssentials/RefactoringEssentials.2017/RefactoringEssentials.csproj]

The ReadLegacyDependencies target from NuGet.Build.Packaging.Tasks is called when PackOnBuild is set to true.

The NuGet.Build.Packaging.Tasks assembly was loading an embedded NuGet.ProjectModel assembly that conflicts with the version that is used by Microsoft.NET.Build.Tasks.

Support RestoreAdditionalProjectFallbackFolders MSBuild Property

The RestoreAdditionalProjectFallbackFolders MSBuild property is read and appended to the list of fallback folders stored in the project.assets.json file. The .NET Core 2.0 SDK will set this MSBuild property to point to the NuGet package fallback folder that is installed with the SDK. This will be used to resolve NuGet packages first before downloading them to the ~/.nuget/packages folder.

Support RestoreAdditionalProjectSources MSBuild Property

The RestoreAdditionalProjectSources MSBuild property can be used to add additional package sources to the existing list of sources used to resolve packages.

Support RestoreFallbackFolders MSBuild Property

The RestoreFallbackFolders MSBuild property can be used by project that uses PackageReferences to define a set of package fallback folders that will override any specified in the NuGet.Config file. It can also be used to clear any pre-defined fallback folders by specifying ‘clear’ as its value. Note that this value does not affect any folders defined by RestoreAdditionalProjectFallbackFolders which will be appended even if RestoreFallbackFolders is set to ‘clear’.

Support RestorePackagesPath MSBuild Property

The RestorePackagesPath MSBuild property can be used to override the global packages folder location when a project uses a PackageReference.

Support RestoreSources MSBuild property

The RestoreSources MSBuild property can be used to override the sources defined by any NuGet.Config file. Any sources defined in the RestoreAdditionalProjectSources MSBuild property will still be appended to the list of sources if RestoreSources is defined.

Bug Fixes

Transitive dependencies not available when using project.json

With two projects A and B that both use project.json files, project B referencing project A, the NuGet package dependencies used by project A were not available to project B transitively. This was because the project reference information was not being used when a restore occurred. This caused the assemblies from the transitively referenced NuGet packages to not be added to the project.lock.json file for Project B.

Unable to debug a new Azure Functions project without re-opening project

After creating a new Azure Functions project it was possible to build the project but not to debug it or run it. On closing and re-opening the solution it would be possible to debug and run the Azure Functions project.

When Visual Studio for Mac created a new Azure Functions project it initially determined that it could not run or debug the project. After the Azure Functions project has its PackageReferences restored it gains an AzureFunctions project capability. This capability is used to determine if the project can be run. This change in the capability was not handled by Visual Studio for Mac so it did not allow the project to be run until the project was closed and re-opened.

Now, after the NuGet package restore is finished, the project is re-evaluated and a check is made to see if the project can now be run.

Fix generated NuGet files being imported twice

The generated ProjectName.nuget.g.targets and ProjectName.nuget.g.props that are created for .NET Core projects in the base intermediate directory were being imported twice when evaluating the project. Once by Microsoft.Common.props, provided with Mono, and once by Visual Studio for Mac.

This duplicate import was resulting in a duplicate file being added to the project held in memory by Visual Studio for Mac when the Xamarin.Forms 2.4 NuGet package was used in a .NET Standard project and no .NET Core SDK is installed. This would result in the content page xaml and associated C# file not being nested in the solution window.

Template Creator for Visual Studio for Mac

The Template Creator extension provides a way to create a project template from an existing project or solution open in Visual Studio for Mac and have the project template available in the New Project dialog straight away.

The Template Creator uses the .NET Core templating engine to create the projects from the project templates.

Let us take a look in more detail at what the Template Creator extension provides in Visual Studio for Mac.

Features

  • Create a project template from an existing solution or project
  • Create custom top level project template categories

Supports

  • Visual Studio Mac 7.0 or later.

Creating a new Project Template

To create a new project template for a project opened in Visual Studio for Mac, right click the project and select Create Template.

Project - Create Template context menu

A Template Information dialog is then opened.

Template Information dialog

The information in the dialog is used to populate the generated template.json file. Further details on what the template.json file holds is available in the reference for template.json].

  • Author
    • Author of the project template.
  • Display Name
    • This is the template name displayed in the New Project dialog.
  • Description
    • This is the description displayed in the New Project dialog.
  • Category
    • This is the category in the New Project dialog used by the template.
  • Short Name
    • This is the short name for the template that can be used from the .NET Core command line.
  • Default Project Name
    • This is the default project name that will be used with the .NET Core command line.
  • Identity
    • This is the unique id for the template. This should be unique across all custom project templates.
  • Group Identity
    • This is typically a substring of the template’s Identity.

By default the project template will use the Other – .NET – General category in the New Project dialog. To change the category click the browse button next to the category text box to open the Template Categories dialog.

Template Categories dialog

Select the required category and click OK. The selected category will then be updated in the Template Information dialog.

Click OK to generate the template.json file. The template.json file will be opened in the text editor. It will also be displayed in the Solution window in the .template.config folder.

template.json file created for project

The project template is now available in the New Project dialog.

Custom template in New Project dialog

Updating a Project Template

After the project template is created you can modify the original project and its template.json file as required.

Changes made to the project are available in the New Project dialog immediately.

Changes made to the template.json file are available immediately in the same instance of Visual Studio for Mac where the template.json file is being edited.

Multiple Projects in a Template

A project template may create more than one project. To create a project template for all projects in the solution right click the solution and select Create Template.

Solution - Create Template context menu

A template.json file will be created in a .template.config directory inside the solution’s directory.

template.json file created for solution

Note that in order for the new projects created to use the name specified in the New Project dialog they should all have a common start to their name. The template.json file’s sourceName will be the part that is replaced with the name of the project specified in the New Project dialog.

Configuring Registered Project Templates

The .NET Core templating engine supports project templates in NuGet packages or project templates that unpackaged in a directory. The Template Creator extension does not package the project templates into a NuGet package and instead stores a set of directories that are scanned by the .NET Core templating engine for templates. The set of directories that are registered can be viewed and updated in the Preferences dialog from the Templates – Custom Folders section.

Preferences dialog - Templates - Custom Folders

The templating engine will scan the configured directories and look for all the template.json files which define the project templates. The project templates found are then made available to the Visual Studio for Mac’s New Project dialog by the Template Creator extension.

When the template.json file is created using the information in the Template Information dialog the Template Creator extenxion also registers the project’s directory so it will be scanned by the templating engine.

To remove a project template from the New Project dialog you can either delete the template.json file or remove the folder from the Custom Folders defined in the Preferences dialog.

If you have an existing set of project templates that use template.json files and are not in a NuGet package then you can register a single parent directory in the Preferences dialog.

Custom Categories

Custom top level categories can be defined for your project templates by adding them in Preferences – Templates – Custom Categories.

Preferences dialog - Templates - Custom Categories

The Add Top Level Category button will add a new top level category and two child category levels. The New Project dialog requires three category levels. The ids used should ensure that the full path to the template’s category is unique. For example, with a custom category custom/net/general there should not be another top level custom category id, but the second and third level category ids can be re-used in another top level category, such as top/net/general.

The Add Category button will add a single child category to the currently selected category whilst the Remove button will remove the selected category.

Note that changes to the categories require Visual Studio for Mac to be restarted before they are visible in the New Project dialog.

Also note that it is not currently possible to extend existing project template categories using the Template Creator extension.

Diagnosing Template Problems

If the template does not appear in the New Project dialog or fails to be created then you may be able to diagnose the problem by opening the Templating Log window. This is available from the View – Pads menu.

Main menu - View - Templating Log

This window will show messages returned from the .NET Core templating engine and any errors reported by the Template Creator extension.

Templating Log window

Installation

The Template Creator extension is available to download from GitHub.

To install the extension open the Extensions Manager by selecting Extensions… from the main menu. Click the Install from file button. Select the .mpack file and then click the Open button.

The extension is also available in the Extensions Manager from the Visual Studio Extension Repository (Beta channel).

Source Code

Further Reading

.NET Core Support in Visual Studio for Mac 7.2

Changes

  • Support NuGet package fallback folders
  • Support AssetTargetFallback
  • Xamarin.Forms 2.4 support (VS for Mac 7.2.2)
  • Fixed transitive types from references not being available

More information on all the new features and changes in Visual Studio for Mac 7.2 can be found in the release notes.

NuGet package fallback folders support

The .NET Core SDK 2.0 defines a NuGet package fallback folder /usr/local/share/dotnet/sdk/NuGetFallbackFolder that can be used when looking for NuGet packages whilst restoring. This fallback folder is now supported by Visual Studio for Mac 7.2 so that on restoring a .NET Core 2.0 project the NuGet packages from the fallback folder will be found and do not need to be downloaded from nuget.org into the local machine NuGet package cache ~/.nuget/packages. This should speed up NuGet package restore for .NET Core 2.0 and .NET Standard 2.0 projects the first time it occurs.

As well as the NuGet fallback folders Visual Studio for Mac will now add the following items to the generated project.assets.json if they are available:

  • configFilePaths
  • sources
  • warningProperties

AssetTargetFallback support

The .NET Core 2.0 SDK uses an AssetTargetFallback MSBuild property defined in an imported SDK MSBuild files. This is used instead of the PackageTargetFallback property when determining if a NuGet package is compatible. Currently the AssetTargetFallback property is set to net461 by the .NET Core 2.0 SDK which allows .NET Core projects to use NuGet packages that include assemblies that target the full .NET Framework. The supported fallback frameworks are now added to the generated project.assets.json file by Visual Studio for Mac when a .NET Core 2.0 project is restored.

NuGet package restore now fails if package and asset target fallbacks are defined by a project

If both AssetTargetFallback and PackageTargetFallback are defined by a project then the NuGet restore will fail with an error indicating that they cannot be used together. This mirrors the behaviour of the .NET Core command line restore.

Mark implicit PackageReferences as auto referenced

PackageReference items that have IsImplicitlyDefined set to true in their metadata now have autoRefererenced set to true in the project.assets.json file.

Support parsing MSBuild conditions with unquoted properties

The .NET Core 2.0 SDK uses conditions that pass properties to the Exists function without using single quotes around the MSBuild property. This is now supported by Visual Studio for Mac.

<PropertyGroup Condition="Exists($(FileName))">

Xamarin.Forms 2.4 support

The following sections cover bug fixes made in Visual Studio for Mac 7.2.2 to improve support for Xamarin.Forms 2.4 and later versions. Xamarin.Forms 2.4 includes .NET Standard support as well as defining default MSBuild items for .NET Core and .NET Standard projects. These default MSBuild items were not handled by Visual Studio for Mac 7.2.0 and earlier versions. The main symptoms of Visual Studio for Mac not supporting Xamarin.Forms 2.4 were:

  • Duplicate .xaml files in the Solution window.
  • Nesting of .xaml and .xaml.cs files not working in Solution window.
  • MSBuild items incorrectly added to SDK style projects.

Generated NuGet files being imported twice

The generated NuGet files, .nuget.g.targets and .nuget.g.props, that are created for .NET Core projects were being imported twice. Once by Microsoft.Common.props, that is provided with Mono, and once by Visual Studio for Mac.

This double import was causing a duplicate file to be added to the project when Xamarin.Forms 2.4 was used in a .NET Standard project and the .NET Core SDK was not installed. This would result in the .xaml file and associated .xaml.cs file not being nested in the solution window.

MSBuild items added when new xaml file added to project

Adding a new Xamarin.Forms content page with XAML would incorrectly add an update item to the project for the .xaml.cs file when an SDK style project was used.

When a new .xaml file was added to an SDK style project a None item as well as an EmbeddedResource item would incorrectly be added to the project file.

1
2
3
4
5
<None Remove="MyView.xaml" />

<EmbeddedResource Include="MyView.xaml">
  <Generator>MSBuild:UpdateDesignTimeXaml"</Generator>
</EmbeddedResource>

Compile item added with DependentUpon metadata

Xamarin.Forms 2.4 defines a wildcard update similar to:

<Compile Update="**\*.xaml.cs" DependentUpon="%(Filename)" />

When a project was saved in Visual Studio for Mac a Compile item was incorrectly added to the main project with the evaluated value stored in the DependentUpon element.

DependentUpon being evaluated incorrectly

Metadata defined for wildcard MSBuild items were being evaluated using the wildcard item instead of the expanded item. This was causing .xaml.cs files to not be nested in the Solution window for Xamarin.Forms 2.4.

Xamarin.Forms 2.4 defines an update item similar to:

<Compile Update="**\*.xaml.cs" DependentUpon="%(Filename)" />

The DependentUpon property was evaluated using the wildcard item which resulted in the DependentUpon property being evaluated as ‘*.xaml.cs’ instead of the filename of the item that was updated by the wildcard.

Define MSBuildSDKsPath for MSBuild engine host

MSBuild when run on the command line defines the MSBuildSDKsPath in its MSBuild.dll.config file. The MSBuild engine host that is used when building with Visual Studio for Mac now also defines the MSBuildSDKsPath property. Previously this was not being defined.

This fixes a build error when using Xamarin.Forms 2.4.0 in an SDK style project that targets .NET Standard. Xamarin.Forms 2.4.0 uses default item imports which were not being included since they are conditionally imported based on the MSBuildSDKsPath property value:

<Import Project="$(MSBuildThisFileDirectory)Xamarin.Forms.DefaultItems.props" 
    Condition="'$(MSBuildSDKsPath)'!=''" />

If the SDK style project had a .xaml file and a .xaml.cs file then the .xaml.g.cs file was not being generated when the project had no files explicitly defined in the project file. This then caused a build error about the InitializeComponent method not being defined.

Bug Fixes

Fixed transitive assembly references not available until restart

Given a solution that contains three .NET Standard projects: LibC references LibB which references LibA. If the Newtonsoft.Json NuGet package was installed into LibA the types from this NuGet package were not available in LibB or LibC until the solution was closed and re-opened again. Closing and re-opening the solution refreshes the reference information used by the type system. Now when a NuGet package is installed into a .NET Core project the projects that reference this project have their reference information refreshed. Types from the installed NuGet packages are then available in projects that reference this updated project either directly or indirectly.

Fixed transitive project references after editing a project file

Given a solution that contains three .NET Standard projects: LibC references LibB which references LibA. If a NuGet package is added to LibA by editing its project file in the text editor the types from this NuGet package were not available to LibB or LibC without restarting Visual Studio for Mac or until the packages were restored for the solution. Now when the project file is saved the projects that directly or indirectly reference the project will be restored.

Ignore project references with ReferenceOutputAssembly set to false when restoring

Project references that have ReferenceOutputAssembly are now not added to the project.assets.json file. This was causing the NuGet package restore to fail in some cases. For example, if a .NET Standard project has a project reference to a .NET Core App project, but has the ReferenceOutputAssembly set to false, then running dotnet restore from the command line would work, but the restore would fail in Visual Studio for Mac.

NuGet Support in Visual Studio for Mac 7.2

Changes

  • NuGet 4.3.1 support
  • NuGet fallback folders support
  • AssetTargetFallback support
  • NuGet operations can be cancelled on closing the solution
  • Fixed transitive types from references not being available
  • Fixed credential dialog being shown multiple times on opening a solution

More information on all the new features and changes in Visual Studio for Mac 7.2 can be found in the release notes.

NuGet 4.3.1 support

NuGet 4.3.1.4445 is now included with Visual Studio for Mac 7.2.

NuGet 4.3.1 includes a fix for imports in the project.json file being ignored which could cause a NuGet package to incorrectly be considered incompatible when restoring NuGet packages.

NuGet package fallback folders support

The .NET Core SDK 2.0 defines a NuGet package fallback folder /usr/local/share/dotnet/sdk/NuGetFallbackFolder that can be used when looking for NuGet packages whilst restoring. This fallback folder is now supported by Visual Studio for Mac 7.2 so that on restoring a .NET Core 2.0 project the NuGet packages from the fallback folder will be found and do not need to be downloaded from nuget.org into the local machine NuGet package cache ~/.nuget/packages. This should speed up NuGet package restore for .NET Core 2.0 and .NET Standard 2.0 projects the first time it occurs.

As well as the NuGet fallback folders Visual Studio for Mac will now add the following items to the generated project.assets.json if they are available:

  • configFilePaths
  • sources
  • warningProperties

AssetTargetFallback support

The .NET Core 2.0 SDK uses an AssetTargetFallback MSBuild property defined in an imported SDK MSBuild files. This is used instead of the PackageTargetFallback property when determining if a NuGet package is compatible. Currently the AssetTargetFallback property is set to net461 by the .NET Core 2.0 SDK which allows .NET Core projects to use NuGet packages that include assemblies that target the full .NET Framework. The supported fallback frameworks are now added to the generated project.assets.json file by Visual Studio for Mac when a .NET Core 2.0 project is restored.

NuGet operations can be cancelled on the closing the solution

Previously when closing the solution, or closing Visual Studio for Mac, when a NuGet package operation was still running would result in a dialog being displayed saying that the solution cannot be closed until the NuGet operation was completed. NuGet v3 and above now allow the NuGet operations to be cancelled so now the dialog allows the current operation to be cancelled. If the operation is taking a while to cancel a busy spinner image will be displayed in the dialog.

Cancel NuGet operation dialog on closing solution

If a restore is being run when the solution will be closed the restore will be cancelled automatically without showing the dialog.

NuGet package restore now fails if package and asset target fallbacks are defined by a project

If both AssetTargetFallback and PackageTargetFallback are defined by a project then the NuGet restore will fail with an error indicating that they cannot be used together. This mirrors the behaviour of the .NET Core command line restore.

Support imported package references in non .NET Core projects

If a non .NET Core project had no PackageReference items but imported a file that did have PackageReference items the NuGet packages were not restored on opening the solution. This was because only the PackageReference items defined directly in the project were checked to determine if the project used NuGet packages. Now the evaluated MSBuild items are checked so any imported PackageReference items are detected and a restore will be run on opening the solution.

Note that imported PackageReference items are not displayed in the Packages folder.

Package Console is no longer opened when a NuGet operation is cancelled

When a NuGet operation is cancelled from the main status bar the Package Console is now not opened when the NuGet operation fails due to the cancellation. If the NuGet operation is not cancelled then the Package Console window will still be opened as before if the operation fails. This is also a workaround for Visual Studio for Mac closing the currently displayed dialog when the Package Console window opens after the NuGet operation is cancelled when closing the solution.

Whitespace is now trimmed when creating a new package source

When creating a new package source copying and pasting NuGet package source url can sometimes copy extra whitespace which can then result in NuGet package restore errors such as:

Failed to verify the root directory of local source
' https://api.nuget.org/v3/index.json'.

The package source name and url will now have whitespace trimmed to avoid this copy and paste problem. This also matches Visual Studio on Windows behaviour.

Mark implicit PackageReferences as auto referenced

PackageReference items that have IsImplicitlyDefined set to true in their metadata now have autoRefererenced set to true in the project.assets.json file.

Bug Fixes

Fixed transitive assembly references not available until restart

Given a solution that contains three .NET Standard projects: LibC references LibB which references LibA. If the Newtonsoft.Json NuGet package was installed into LibA the types from this NuGet package were not available in LibB or LibC until the solution was closed and re-opened again. Closing and re-opening the solution refreshes the reference information used by the type system. Now when a NuGet package is installed into a .NET Core project the projects that reference this project have their reference information refreshed. Types from the installed NuGet packages are then available in projects that reference this updated project either directly or indirectly.

Fixed transitive project references after editing a project file

Given a solution that contains three .NET Standard projects: LibC references LibB which references LibA. If a NuGet package is added to LibA by editing its project file in the text editor the types from this NuGet package were not available to LibB or LibC without restarting Visual Studio for Mac or until the packages were restored for the solution. Now when the project file is saved the projects that directly or indirectly reference the project will be restored.

Fixed credential dialog shown multiple times on opening a solution

With check for updates enabled, multiple projects in the solution, and a package source that was missing or had invalid credentials, on opening the solution the credential dialog would be displayed multiple times even if the correct username and password was entered or the dialog was cancelled. The dialog was being displayed for each project and the credential information was not being re-used.

Now the NuGet source repositories are re-used when checking for updates and also when restoring the projects when the solution is first opened. Any valid credentials entered will be re-used when checking the remaining projects. If the credential dialog is cancelled then the dialog is no longer displayed again whilst checking for updates for the other projects.

Fixed credential dialog displayed when credentials are available

With valid credentials stored in the Mac key chain the credential dialog would still be displayed when it should not have been. The problem was that the NuGet credential service puts itself in a retry mode if any of the credential providers are used when trying to authenticate against a package source. Once in this retry mode the Visual Studio for Mac credential provider would always show a dialog asking for the credentials instead of re-using the existing credentials. To avoid this the credential service is reset before any user actions, such as opening the Add Packages dialog, running a restore or an update.

Fixed crash when displaying Chinese characters in the Add Packages dialog

With the NuGet v3 package source https://api.nuget.org/v3/index.json selected, searching for Microsoft.AspNet.WebApi.Client would result in the Visual Studio for Mac terminating when an attempt was made to display the results in the Add Packages dialog. The crash was in the Pango library when it attempted to determine the size of the package title displayed in the search results. If the package title contained Chinese characters then Pango would throw an exception:

Illegal byte sequence encounted in the input.
at (wrapper managed-to-native) Pango.Layout:pango_layout_get_pixel_size (intptr,int&,int&)

Then when Visual Studio for Mac tried to use Pango again to determine the size of the text this would result in Visual Studio for Mac terminating.

1
2
3
4
5
6
Pango-WARNING (recursed) **: shaping failure, expect ugly output.
shape-engine='BasicEngineCoreText', font='.SF NS Text',
text='∫ê'Stacktrace:

  at <unknown> <0xffffffff>
  at (wrapper managed-to-native) Pango.Layout.pango_layout_get_pixel_size (intptr,int&,int&) [0x0000b] in <c7aa2d93df4045df8dc71d5439f99d72>:0

If the NuGet v2 package source was used then this crash did not occur since the package title was not returned in the search results and the package id would be displayed instead which does not contain Chinese characters.

As a workaround the Add Packages dialog now displays the package id instead of the package title.

Ignore project references with ReferenceOutputAssembly set to false when restoring

Project references that have ReferenceOutputAssembly are now not added to the project.assets.json file. This was causing the NuGet package restore to fail in some cases. For example, if a .NET Standard project has a project reference to a .NET Core App project, but has the ReferenceOutputAssembly set to false, then running dotnet restore from the command line would work, but the restore would fail in Visual Studio for Mac.